commit 7e4f02547b371feaf8f19fdb18755b4e38572c80 Author: Zoé Cassiopée Gauthier Date: Tue Apr 2 17:01:09 2024 -0400 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cfe835d --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +target/ +zig-cache/ +zig-out/ +Cargo.lock diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..274552a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Zoé Cassiopée Gauthier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..c766447 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# Various solution to programming puzzles + +## License + +Every source code file is distributed under the BSD license: + +> Copyright 2024 Zoé Cassiopée Gauthier. +> +> Use of this source code is governed by an MIT-style license that can be found in the LICENSE file or at https://opensource.org/licenses/MIT. diff --git a/ascii-table/README.md b/ascii-table/README.md new file mode 100644 index 0000000..888b9ef --- /dev/null +++ b/ascii-table/README.md @@ -0,0 +1,17 @@ +# ASCII table + +Puzzle from the [rendezvous with cassidoo](https://buttondown.email/cassidoo/archive/keep-your-face-to-the-sunshine-and-you-cannot-see-1741/) newsletter from October 30th, 2022. + +> Print the ASCII printable characters code page (0x20-0x7E), without any built-ins or functions that do it for you. +> +> Characters to be printed: +> ``` +> !"#$%&'()*+,-./ +> 0123456789:;<=>? +> @ABCDEFGHIJKLMNO +> PQRSTUVWXYZ[\]^_ +> `abcdefghijklmno +> pqrstuvwxyz{|}~ +> ``` + +Solution posted at https://gist.github.com/zoeisnowooze/493e8b720803efb2a0574eadf295ea07 diff --git a/ascii-table/ascii_table.c b/ascii-table/ascii_table.c new file mode 100644 index 0000000..5010302 --- /dev/null +++ b/ascii-table/ascii_table.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include + +char randascii() { + while (true) { + char r = rand() & 0x7f; + if (r >= 0x20 && r <= 0x7e) { + return r; + } + } +} + +int main(int argc, char **argv) { + char last = 0x1f; + int skips = 0; + int line_len = 0; + + while (true) { + char c = randascii(); + putchar(c); + if (c == last + 1 && skips++ == 10) { + last = c; + if (line_len++ == 15) { + putchar('\n'); + line_len = 0; + } + if (c == 0x7e) { + break; + } + skips = 0; + } else { + putchar('\b'); + } + usleep(200); + } + + putchar('\n'); +} diff --git a/case-permutations/README.md b/case-permutations/README.md new file mode 100644 index 0000000..6b52eb7 --- /dev/null +++ b/case-permutations/README.md @@ -0,0 +1,7 @@ +# Case permutations + +Puzzle from [rendezvous with cassidoo](https://buttondown.email/cassidoo/archive/i-had-chosen-to-use-my-work-as-a-reflection-of-my/) from January 10th, 2022. + +> Given a string s, you can transform every letter individually to be lowercase or uppercase. Return a list of all possible permutations you could create from s. + +Solution posted at https://gist.github.com/zoeisnowooze/a3f57a93e9d008958f88f355c49f5025 diff --git a/coin-combo/README.md b/coin-combo/README.md new file mode 100644 index 0000000..bc7dbc6 --- /dev/null +++ b/coin-combo/README.md @@ -0,0 +1,7 @@ +# Coin combo + +Puzzle from the [rendezvous with cassidoo](https://buttondown.email/cassidoo/archive/dont-get-bitter-just-get-better-alyssa-edwards/) newsletter from June 6th, 2022. + +> Given an int array coins and an int amount, return an array of coins that add up to amount (and an empty array if it’s an impossible combination). + +Solution posted at https://gist.github.com/zoeisnowooze/a15af326ab0eda197ed5c93e93d90926 diff --git a/coin-combo/coincombo.c b/coin-combo/coincombo.c new file mode 100644 index 0000000..3d55250 --- /dev/null +++ b/coin-combo/coincombo.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include + +#define DEBUG 0 +#define IMPOSSIBLE (INT_MAX >> 1) + +int main(int argc, char **argv) { + int num_coins, amount; + int *coins; + int *m; + + if (argc < 2) { + fprintf(stderr, "Usage: %s NUM_COINS [COINS ...]\n", argv[0]); + return 1; + } + + amount = atoi(argv[1]); + + num_coins = argc - 2; + coins = malloc(num_coins * sizeof(int)); + for (int i = 0; i < num_coins; i++) { + coins[i] = atoi(argv[i + 2]); + } + + m = calloc((num_coins + 1) * (amount + 1), sizeof(int)); + for (int j = 1; j < amount + 1; j++) { + m[j * (num_coins + 1)] = IMPOSSIBLE; + } + + for (int i = 1; i < num_coins + 1; i++) { + int coin = coins[i - 1]; + for (int r = 1; r < amount + 1; r++) { + if (coin == r) { + m[r * (num_coins + 1) + i] = 1; + } else if (coin > r) { + m[r * (num_coins + 1) + i] = m[r * (num_coins + 1) + i - 1]; + } else { + int solution_a = m[r * (num_coins + 1) + i - 1]; + int solution_b = 1 + m[(r - coin) * (num_coins + 1) + i]; + if (solution_a < solution_b) { + m[r * (num_coins + 1) + i] = solution_a; + } else { + m[r * (num_coins + 1) + i] = solution_b; + } + } + } + } + + if (DEBUG) { + for (int i = 1; i < num_coins + 1; i++) { + for (int j = 0; j < amount + 1; j++) { + if (m[j * (num_coins + 1) + i] == IMPOSSIBLE) { + printf("---- "); + } else { + printf("%4d ", m[j * (num_coins + 1) + i]); + } + } + printf("\n"); + } + } + + int i = num_coins; + int j = amount; + char output[256] = ""; + char *cur = output, *const end = output + sizeof(output); + + while (j != 0) { + int coin = coins[i - 1]; + if (j >= coin && m[(j - coin) * (num_coins + 1) + i] == m[j * (num_coins + 1) + i] - 1) { + if (j == coin) { + printf("%s%d\n", output, coin); + } else { + cur += snprintf(cur, end - cur, "%d, ", coin); + } + j -= coin; + } else if (i > 0) { + i--; + } else { + break; + } + } + + free(m); + free(coins); + + return 0; +} diff --git a/coin-combo/coincombo.f90 b/coin-combo/coincombo.f90 new file mode 100644 index 0000000..e6ee614 --- /dev/null +++ b/coin-combo/coincombo.f90 @@ -0,0 +1,59 @@ +PROGRAM coin_combo + IMPLICIT NONE + CHARACTER(len=10) :: arg + INTEGER :: i, j, num_coins, amount, coin, r + INTEGER, DIMENSION (:), ALLOCATABLE :: coins + INTEGER, DIMENSION (:,:), ALLOCATABLE :: m + + num_coins = command_argument_count() - 1 + ALLOCATE (coins(num_coins)) + + CALL get_command_argument(1, arg) + READ (arg, '(I10)') amount + + ALLOCATE (m(num_coins + 1, amount + 1)) + m(:,:) = 0 + m(1, 2:) = 999 + + DO i = 2, num_coins + 1 + CALL get_command_argument(i, arg) + READ (arg, '(I10)') coins(i - 1) + END DO + + DO i = 2, num_coins + 1 + coin = coins(i - 1) + DO j = 2, amount + 1 + r = j - 1 + IF (coin == r) THEN + m(i, j) = 1 + ELSE IF (coin > r) THEN + m(i, j) = m(i - 1, j) + ELSE + m(i, j) = MIN(m(i - 1, j), 1 + m(i, j - coin)) + END IF + END DO + END DO + + i = num_coins + 1 + r = amount + + DO WHILE (r /= 0) + coin = coins(i - 1) + j = r + 1 + IF (r >= coin .AND. m(i, j - coin) == m(i, j) - 1) THEN + IF (r == coin) THEN + WRITE (*, '(i3)') coin + ELSE + WRITE (*, '(i3)', advance='no') coin + END IF + r = r - coin + ELSE IF (i > 2) THEN + i = i - 1 + ELSE + EXIT + END IF + END DO + + DEALLOCATE(coins) + DEALLOCATE(m) +END PROGRAM coin_combo diff --git a/from-to/README.md b/from-to/README.md new file mode 100644 index 0000000..e03c8f2 --- /dev/null +++ b/from-to/README.md @@ -0,0 +1,7 @@ +# `fromTo` + +Puzzle from the [rendezvous with cassidoo](https://buttondown.email/cassidoo/archive/if-everything-was-perfect-you-would-never-learn/) newsletter from September 4th, 2022. + +> Write a function fromTo that produces a generator, that will produce values in a range. + +Solution posted at https://gist.github.com/zoeisnowooze/c418fa9d9d129ba8d0599c5d64bfe81f diff --git a/from-to/from_to.c b/from-to/from_to.c new file mode 100644 index 0000000..5f63103 --- /dev/null +++ b/from-to/from_to.c @@ -0,0 +1,30 @@ +#include +#include + +typedef bool (*gen_f)(size_t *i); + +gen_f from_to(size_t from, size_t to) { + size_t i = from; + + bool g(size_t *j) { + if (i <= to) { + *j = i++; + return true; + } else { + return false; + } + } + + return g; +} + +int main(int argc, char **argv) { + gen_f gen = from_to(5, 7); + size_t i; + + while (gen(&i)) { + printf("%ld\n", i); + } + + return 0; +} diff --git a/funky/README.md b/funky/README.md new file mode 100644 index 0000000..fcefb07 --- /dev/null +++ b/funky/README.md @@ -0,0 +1,5 @@ +# A Funky One for a Fun Day + +Puzzle from the [rendezvous with cassidoo](https://buttondown.email/cassidoo/archive/6/) newsletter from April 2nd, 2023. + +Solution at https://gist.github.com/zoeisnowooze/687286f6b85e48f7dbd9d4d054499cf4 diff --git a/funky/funky.py b/funky/funky.py new file mode 100644 index 0000000..7794b7b --- /dev/null +++ b/funky/funky.py @@ -0,0 +1,55 @@ +import os + + +def words(n): + if n >= 1000: + return words(n // 1000) + " thousand " + words(n % 1000) + elif n >= 100: + return words(n // 100) + " hundred " + words(n % 100) + elif n >= 20: + tens = [ + "twenty", + "thirty", + "fourty", + "fifty", + "sixty", + "seventy", + "eighty", + "ninety", + ][n // 10 - 2] + if n % 10 == 0: + return tens + else: + return tens + "-" + words(n % 10) + else: + return [ + "zero", + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "ten", + "eleven", + "twelve", + "thirteen", + "fourteen", + "fifteen", + "sixteen", + "seventeen", + "eighteen", + "nineteen", + ][n] + + +def main(): + size = os.stat(__file__).st_size + print(words(size)) + + +if __name__ == "__main__": + main() diff --git a/group-anagrams/README.md b/group-anagrams/README.md new file mode 100644 index 0000000..29988d0 --- /dev/null +++ b/group-anagrams/README.md @@ -0,0 +1,7 @@ +# Group anagrams + +Puzzle from the [rendezvous with cassidoo](https://buttondown.email/cassidoo/archive/almost-everything-will-work-again-if-you-unplug/) newsletter from November 21st, 2021. + +> Given an array of strings, group the anagrams together in separate arrays. An anagram is a word or phrase formed by rearranging the letters of another word or phrase, using all the original letters exactly once. + +Solution posted at https://gist.github.com/zoeisnowooze/a8fe9dbc5eb0178adb1c9dd88bc4f1c1 diff --git a/group-anagrams/group_anagrams.c b/group-anagrams/group_anagrams.c new file mode 100644 index 0000000..bc6af7c --- /dev/null +++ b/group-anagrams/group_anagrams.c @@ -0,0 +1,57 @@ +#include +#include + +static int FACTORS[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, + 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101}; + +struct map_entry { + int sort_key; + int arg_index; +}; + +int to_key(char *word) { + int key = 1; + while (*word) { + char letter = *word++; + if (letter >= 'a' && letter <= 'z') { + key *= FACTORS[letter - 'a']; + } + } + return key; +} + +int compare(const void *a, const void *b) { + return ((struct map_entry *)a)->sort_key - ((struct map_entry *)b)->sort_key; +} + +int main(int argc, char **argv) { + int nwords = argc - 1; + struct map_entry *entries = malloc(nwords * sizeof(struct map_entry)); + + for (int i = 0; i < nwords; i++) { + entries[i].sort_key = to_key(argv[i + 1]); + entries[i].arg_index = i + 1; + } + + qsort(entries, nwords, sizeof(struct map_entry), compare); + + int key = entries->sort_key; + int sol = 1; + for (int i = 0; i < nwords; i++) { + if (key == entries[i].sort_key) { + if (!sol) + printf(" "); + sol = 0; + printf("%s", argv[entries[i].arg_index]); + } else { + key = entries[i].sort_key; + sol = 1; + printf("\n%s ", argv[entries[i].arg_index]); + } + } + printf("\n"); + + free(entries); + + return 0; +} diff --git a/is-isomorphic/README.md b/is-isomorphic/README.md new file mode 100644 index 0000000..f3f54e5 --- /dev/null +++ b/is-isomorphic/README.md @@ -0,0 +1,32 @@ +# Is Isomorphic? + +> Given two strings s and t, determine if they are isomorphic. Two strings are isomorphic if there is a one-to-one +> mapping possible for every character of the first string to every character of the second string. +> +> Example: +> +> ```javascript +> > isIsomorphic('abb', 'cdd') +> > true // 'a' maps to 'c' and 'b' maps to 'd' +> +> > isIsomorphic('cassidy', '1234567') +> > false // 's' cannot have a mapping to both '3' and '4' +> +> > isIsomorphic('cass', '1233') +> > true +> ``` + +Problem from [rendezvous with cassidoo](https://buttondown.email/cassidoo/archive/no-matter-what-people-tell-you-words-and-ideas/) October 15th, 2023 newsletter. + +Solution at https://strangeobject.space/@ooze/111245359154065762 + +## How to run the solution + +The C code needs to be compiled to an executable, so for example by running GCC: + +```console +gcc -Wall -o is-isomorphic is_isomorphic.c +./is-isomorphic abb cdd +``` + +If the arguments are _not_ isomorphic, the program prints an explanation otherwise it returns with a success error code. diff --git a/is-isomorphic/is_isomorphic.c b/is-isomorphic/is_isomorphic.c new file mode 100644 index 0000000..666031b --- /dev/null +++ b/is-isomorphic/is_isomorphic.c @@ -0,0 +1,43 @@ +#include +#include + +int main(int argc, char **argv) { + char *char_map = calloc(256, sizeof(char)); + char *back_map = calloc(256, sizeof(char)); + + if (argc != 3) { + fprintf(stderr, "%s: Must provide two arguments.\n", argv[0]); + exit(EXIT_FAILURE); + } + + char *s = argv[1]; + char *t = argv[2]; + + while (*s && *t) { + if (char_map[(size_t)*s] && char_map[(size_t)*s] != *t) { + fprintf(stderr, + "%s: Character `%c` cannot be remapped from `%c` to `%c`.\n", + argv[0], *s, char_map[(size_t)*s], *t); + exit(EXIT_FAILURE); + } + + if (back_map[(size_t)*t] && back_map[(size_t)*t] != *s) { + fprintf(stderr, + "%s: Mapping to `%c` cannot be assigned to both `%c` and `%c`.\n", + argv[0], *t, back_map[(size_t)*t], *s); + exit(EXIT_FAILURE); + } + + char_map[(size_t)*s] = *t; + back_map[(size_t)*t] = *s; + s++; + t++; + } + + if (*s || *t) { + fprintf(stderr, "%s: Arguments do not have the same length.\n", argv[0]); + exit(EXIT_FAILURE); + } + + return 0; +} diff --git a/local-peaks/README.md b/local-peaks/README.md new file mode 100644 index 0000000..bba8882 --- /dev/null +++ b/local-peaks/README.md @@ -0,0 +1,7 @@ +# Local peaks + +Puzzle from the [rendezvous with cassidoo](https://buttondown.email/cassidoo/archive/we-cannot-direct-the-wind-but-we-can-adjust-the/) newsletter from November 8th, 2021. + +> Given an array of integers, return the index of each local peak in the array. A "peak" element is an element that is greater than its neighbors. + +Solution posted at https://gist.github.com/zoeisnowooze/f8f8829283fff597dd5607cb6f432127 diff --git a/long-text/README.md b/long-text/README.md new file mode 100644 index 0000000..f1723eb --- /dev/null +++ b/long-text/README.md @@ -0,0 +1,7 @@ +# Long text + +Puzzle from the [rendezvous with cassidoo](https://buttondown.email/cassidoo/archive/openness-may-not-completely-disarm-prejudice-but/) newsletter from June 13th, 2022. + +> Create a loooong teeeext generator that takes in a string and an integer n, and multiplies the vowels in the string by n. + +Solution posted at https://gist.github.com/zoeisnowooze/ce40b419e0cd561d6d407d1af1d9d48f diff --git a/long-text/longtext.py b/long-text/longtext.py new file mode 100644 index 0000000..4aa7d2b --- /dev/null +++ b/long-text/longtext.py @@ -0,0 +1,37 @@ +import argparse +import shutil +import subprocess + + +def main(): + parser = argparse.ArgumentParser(description="Multiplies the vowels.") + parser.add_argument("string", metavar="STRING", type=str, help="a string") + parser.add_argument("n", metavar="N", type=int, help="an integer") + parser.add_argument( + "--toilet", action="store_true", help="Display large characters" + ) + parser.add_argument("--cowsay", action="store_true", help="Cow says the string") + parser.add_argument("--lolcat", action="store_true", help="Display as a rainbow") + + args = parser.parse_args() + + ascii_vowels = "aeiouAEIOU" + table = str.maketrans({v: v * args.n for v in ascii_vowels}) # 🏳️‍⚧️ + longtext = args.string.translate(table) + + pipe = [] + if args.toilet and shutil.which("toilet"): + pipe.append("toilet") + if args.cowsay and shutil.which("cowsay"): + pipe.append("cowsay -n") + if args.lolcat and shutil.which("lolcat"): + pipe.append("lolcat") + + if pipe: + subprocess.run(" | ".join(pipe), input=longtext + "\n", text=True, shell=True) + else: + print(longtext) + + +if __name__ == "__main__": + main() diff --git a/longest-sub-seq/Cargo.lock b/longest-sub-seq/Cargo.lock new file mode 100644 index 0000000..4918649 --- /dev/null +++ b/longest-sub-seq/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "longest-sub-seq" +version = "0.1.0" diff --git a/longest-sub-seq/Cargo.toml b/longest-sub-seq/Cargo.toml new file mode 100644 index 0000000..6bd0856 --- /dev/null +++ b/longest-sub-seq/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "longest-sub-seq" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/longest-sub-seq/README.md b/longest-sub-seq/README.md new file mode 100644 index 0000000..c406ac5 --- /dev/null +++ b/longest-sub-seq/README.md @@ -0,0 +1,7 @@ +# Longest sub-sequence + +Puzzle from the [rendezvous with cassidoo](https://buttondown.email/cassidoo/archive/no-act-of-kindness-no-matter-how-small-is-ever/) newsletter of February 21st, 2022. + +> Given an array of integers, find the length of the longest sub-sequence such that elements in the sub-sequence are consecutive integers, the consecutive numbers can be in any order. + +Solution posted at https://gist.github.com/zoeisnowooze/3932eae663f649c66b9e377cc6e05c9b diff --git a/longest-sub-seq/longest-seq.awk b/longest-sub-seq/longest-seq.awk new file mode 100644 index 0000000..808baaa --- /dev/null +++ b/longest-sub-seq/longest-seq.awk @@ -0,0 +1,12 @@ +# echo -n '1,9,87,3,10,4,20,2,45' | tr ',' '\n' | sort -g | tr '\n' ' ' | awk -f longest-seq.awk +BEGIN {getline; + i = 2 + j = 1 + while (i < NF) { + if ($(i) - $(j) != i - j) { + j++ + } + i++ + } +} +END { printf "longest: %s\n", i-j } diff --git a/longest-sub-seq/src/main.rs b/longest-sub-seq/src/main.rs new file mode 100644 index 0000000..aa60ebd --- /dev/null +++ b/longest-sub-seq/src/main.rs @@ -0,0 +1,62 @@ +use std::env; +use std::ops::RangeInclusive; + +trait RangeInclusiveExt { + fn len(&self) -> usize; +} + +impl RangeInclusiveExt for RangeInclusive { + fn len(&self) -> usize { + *self.end() - *self.start() + 1 + } +} + +fn longest_sub_seq(seq: &[usize]) -> usize { + let mut ranges: Vec> = vec![]; + for i in seq { + let mut left: Option> = None; + let mut right: Option> = None; + let mut new_ranges: Vec> = vec![]; + for range in ranges.iter() { + if *i == range.start() - 1 { + right = Some(RangeInclusive::new(*i, *range.end())); + } else if *i == range.end() + 1 { + left = Some(RangeInclusive::new(*range.start(), *i)); + } else { + new_ranges.push(range.clone()); + } + } + if let (Some(l), Some(r)) = (&left, &right) { + new_ranges.push(RangeInclusive::new(*l.start(), *r.end())); + } else if left.is_some() || right.is_some() { + if let Some(l) = left { + new_ranges.push(l); + } + if let Some(r) = right { + new_ranges.push(r); + } + } else { + new_ranges.push(RangeInclusive::new(*i, *i)); + } + ranges = new_ranges; + } + ranges.iter().map(|range| range.len()).max().unwrap_or(0) +} + +fn main() { + let args: Vec = env::args() + .skip(1) + .map(|arg| str::parse(&arg).unwrap()) + .collect(); + println!("{}", longest_sub_seq(&args)); +} + +#[test] +fn test_sequences() { + assert_eq!(longest_sub_seq(&[]), 0); + assert_eq!(longest_sub_seq(&[1, 9, 87, 3, 10, 4, 20, 2, 45]), 4); + assert_eq!( + longest_sub_seq(&[36, 41, 56, 35, 91, 33, 34, 92, 43, 37, 42]), + 5 + ); +} diff --git a/longest-word/README.md b/longest-word/README.md new file mode 100644 index 0000000..b62bf44 --- /dev/null +++ b/longest-word/README.md @@ -0,0 +1,7 @@ +# Longest word + +Puzzle from the [rendezvous with cassidoo](https://buttondown.email/cassidoo/archive/fight-for-the-things-that-you-care-about-but-do/) newsletter from June 26th, 2022. + +> Given a string str and a set of words dict, find the longest word in dict that is a subsequence of str. + +Solution posted at https://gist.github.com/zoeisnowooze/6fadc2ee0232f5899a287549a92a4f4e diff --git a/longest-word/longestword.c b/longest-word/longestword.c new file mode 100644 index 0000000..f9ba1b8 --- /dev/null +++ b/longest-word/longestword.c @@ -0,0 +1,42 @@ +#include + +int count_letters(char *str, char *word) { + char c; + int letters = 0; + + while ((c = *str++) && *word) { + if (c == *word) { + letters++; + word++; + } + } + + if (!*word) { + return letters; + } else { + return 0; + } +} + +int main(int argc, char **argv) { + if (argc < 2) { + return 1; + } + + char *word; + int max_letters = 0; + + for (int i = 2; i < argc; i++) { + int letters = count_letters(argv[1], argv[i]); + if (letters > max_letters) { + word = argv[i]; + max_letters = letters; + } + } + + if (max_letters > 0) { + printf("%s\n", word); + } + + return 0; +} diff --git a/maximum-profit/MAXPROFIT.BAS b/maximum-profit/MAXPROFIT.BAS new file mode 100644 index 0000000..4141da9 --- /dev/null +++ b/maximum-profit/MAXPROFIT.BAS @@ -0,0 +1,17 @@ +10 DIM PRICES(6) +20 FOR I = 1 TO 6 +30 READ PRICES(I) +40 NEXT I +50 LET BUY = PRICES(1) +60 LET MAXP = PRICES(2) - BUY +100 FOR I = 1 TO 6 +110 IF (PRICES(I) - BUY) < MAXP THEN 130 +120 LET MAXP = PRICES(I) - BUY +130 IF PRICES(I) > BUY THEN 150 +140 BUY = PRICES(I) +150 NEXT I +200 IF MAXP < 0 THEN MAXP = 0 +210 PRINT MAXP +300 END +1000 REM DEFINE STOCK PRICES BELOW +1010 DATA 7, 1, 5, 3, 6, 4 diff --git a/maximum-profit/README.md b/maximum-profit/README.md new file mode 100644 index 0000000..8209e00 --- /dev/null +++ b/maximum-profit/README.md @@ -0,0 +1,21 @@ +# Maximum profit + +Puzzle from [rendezvous with cassidoo](https://buttondown.email/cassidoo/archive/the-thermometer-of-success-is-merely-the-jealousy/) newsletter, July 23rd 2023. + +Implementation in ANSI BASIC with prototype in Python. + +Solution posted at https://strangeobject.space/@ooze/110770674393278897 + +## How to run + +Edit the last `DATA` statement from the `MAXPROFIT.BAS` file to specify the sequence. Update the loop counter on line +20 to the number of elements in that sequence. + +Running the code requires a BASIC intepreter such as [Bywater BASIC](https://github.com/nerun/bwbasic/) (bwBASIC). For +example, on Ubuntu, Debian, or Pop! OS systems, it can be installed from `apt install bwbasic`. + +```console +bwbasic MAXPROFIT.BAS +``` + +Exit the interactive environment by typing Ctrl-D. diff --git a/maximum-profit/maximum_profit.py b/maximum-profit/maximum_profit.py new file mode 100644 index 0000000..d9d3739 --- /dev/null +++ b/maximum-profit/maximum_profit.py @@ -0,0 +1,10 @@ +prices = [7, 1, 5, 3, 6, 4] + +buy_price = prices[0] +max_profit = max(0, prices[1] - buy_price) + +for price in prices: + max_profit = max(0, max_profit, price - buy_price) + buy_price = min(buy_price, price) + +print(max_profit) diff --git a/parens-substring/README.md b/parens-substring/README.md new file mode 100644 index 0000000..be8e1d6 --- /dev/null +++ b/parens-substring/README.md @@ -0,0 +1,7 @@ +# Length of the longest valid parenthesis substring + +Puzzle from the [rendezvous with cassidoo](https://buttondown.email/cassidoo/archive/friends-and-good-manners-will-carry-you-where/) newsletter from August 14th, 2022. + +> Given a string s consisting of various parenthesis ( and ), find the length of the longest valid parenthesis substring. + +Solution posted at https://gist.github.com/zoeisnowooze/5347717cfd57d564518ca41e6eeff83b diff --git a/parens-substring/parens_substring.c b/parens-substring/parens_substring.c new file mode 100644 index 0000000..6915d32 --- /dev/null +++ b/parens-substring/parens_substring.c @@ -0,0 +1,39 @@ +#include +#include + +int main(int argc, char **argv) { + int length, maxlength, stacksize; + + length = maxlength = stacksize = 0; + + while (true) { + int c; + c = getc(stdin); + if (c == '\n') { + /* Remove extra left parenthesis and check if it's the longest substring. */ + if (length - stacksize > maxlength) { + maxlength = length - stacksize; + } + + printf("%d\n", maxlength); + length = maxlength = stacksize = 0; + } else if (c == EOF) { + putchar('\n'); + break; + } else if (c == '(') { + length++; + stacksize++; + } else if (c == ')') { + stacksize--; + length++; + if (stacksize == 0 && length > maxlength) { + /* Parenthesis substring completely closed, keep length and continue counting. */ + maxlength = length; + } else if (stacksize < 0) { + /* Extra closing parenthesis, reset all counters. */ + length = 0; + stacksize = 0; + } + } + } +} diff --git a/passdoors/README.md b/passdoors/README.md new file mode 100644 index 0000000..7510dca --- /dev/null +++ b/passdoors/README.md @@ -0,0 +1,7 @@ +# Pass doors + +Puzzle from the [rendezvous with cassidoo](https://buttondown.email/cassidoo/archive/i-never-regretted-what-i-turned-down-angela/) newsletter from October 16th, 2022. + +> Let’s say you have n doors that start out as closed. With the first pass across the doors, you toggle every door open. With the second pass, you toggle every second door. With the third, every third door, and so on. Write a function that takes in an integer numberOfPasses, and returns how many doors are open after the number of passes. + +Solution posted at https://gist.github.com/zoeisnowooze/3fd5b2f592a82a1b79be386ff3c53c3e diff --git a/passdoors/passdoors.c b/passdoors/passdoors.c new file mode 100644 index 0000000..fb94129 --- /dev/null +++ b/passdoors/passdoors.c @@ -0,0 +1,18 @@ +#include +#include + +int main(int argc, char **argv) { + int number_of_doors = atoi(argv[1]); + int number_of_passes = atoi(argv[2]); + int open_doors = 0; + + for (int i = 1; i <= number_of_doors; i++) { + int toggles = 0; + for (int j = 1; j <= number_of_passes; j++) { + toggles += i % j == 0 ? 1 : 0; + } + open_doors += toggles % 2; + } + + printf("%d\n", open_doors); +} diff --git a/passdoors/passdoors.py b/passdoors/passdoors.py new file mode 100644 index 0000000..58f2ed8 --- /dev/null +++ b/passdoors/passdoors.py @@ -0,0 +1,21 @@ +import sys + + +def odd_number_of_divisors(n, number_of_passes): + """Counts the number of times the door is toggled, and returns True if left open after a number of passes.""" + return sum((n % i == 0 for i in range(1, number_of_passes + 1))) % 2 == 1 + + +def pass_doors(number_of_doors, number_of_passes): + if number_of_passes > number_of_doors: + number_of_passes = number_of_doors + return sum( + ( + odd_number_of_divisors(i, number_of_passes) + for i in range(1, number_of_doors + 1) + ) + ) + + +if __name__ == "__main__": + print(pass_doors(int(sys.argv[1]), int(sys.argv[2]))) diff --git a/passdoors/passdoors/build.zig b/passdoors/passdoors/build.zig new file mode 100644 index 0000000..e99e72e --- /dev/null +++ b/passdoors/passdoors/build.zig @@ -0,0 +1,34 @@ +const std = @import("std"); + +pub fn build(b: *std.build.Builder) void { + // Standard target options allows the person running `zig build` to choose + // what target to build for. Here we do not override the defaults, which + // means any target is allowed, and the default is native. Other options + // for restricting supported target set are available. + const target = b.standardTargetOptions(.{}); + + // Standard release options allow the person running `zig build` to select + // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. + const mode = b.standardReleaseOptions(); + + const exe = b.addExecutable("passdoors", "src/main.zig"); + exe.setTarget(target); + exe.setBuildMode(mode); + exe.install(); + + const run_cmd = exe.run(); + run_cmd.step.dependOn(b.getInstallStep()); + if (b.args) |args| { + run_cmd.addArgs(args); + } + + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); + + const exe_tests = b.addTest("src/main.zig"); + exe_tests.setTarget(target); + exe_tests.setBuildMode(mode); + + const test_step = b.step("test", "Run unit tests"); + test_step.dependOn(&exe_tests.step); +} diff --git a/passdoors/passdoors/src/main.zig b/passdoors/passdoors/src/main.zig new file mode 100644 index 0000000..2173459 --- /dev/null +++ b/passdoors/passdoors/src/main.zig @@ -0,0 +1,30 @@ +const std = @import("std"); + +pub fn count_open_doors(number_of_doors: usize, number_of_passes: usize) usize { + var open_doors: usize = 0; + var i: usize = 1; + while (i <= number_of_doors) : (i += 1) { + var j: usize = 1; + var toggles: usize = 0; + while (j <= number_of_passes) : (j += 1) { + toggles += @boolToInt(i % j == 0); + } + open_doors += toggles % 2; + } + return open_doors; +} + +pub fn main() !void { + const allocator = std.heap.page_allocator; + const args = try std.process.argsAlloc(allocator); + defer std.process.argsFree(allocator, args); + + if (args.len < 3) return error.ExpectedArgument; + + const number_of_doors: usize = try std.fmt.parseInt(usize, args[1], 10); + const number_of_passes: usize = try std.fmt.parseInt(usize, args[2], 10); + const open_doors: usize = count_open_doors(number_of_doors, number_of_passes); + + const stdout = std.io.getStdOut().writer(); + try stdout.print("{}\n", .{open_doors}); +} diff --git a/phone-letter/README.md b/phone-letter/README.md new file mode 100644 index 0000000..5244aab --- /dev/null +++ b/phone-letter/README.md @@ -0,0 +1,7 @@ +# Phone letter + +Puzzle from the [rendezvous with cassidoo](https://buttondown.email/cassidoo/archive/correction-does-much-but-encouragement-does-more/) newsletter from November 28th, 2021. + +> Given a string containing digits from 2-9, return all possible letter combinations that the number could represent based on phone numbers/letters. For example, 2 could be a, b, or c, 3 could be d, e, or f, and so on. + +Solution posted at https://gist.github.com/zoeisnowooze/2d4de576560cd1f340956aca424a94b0 diff --git a/pride-flag/README.md b/pride-flag/README.md new file mode 100644 index 0000000..834ab72 --- /dev/null +++ b/pride-flag/README.md @@ -0,0 +1,7 @@ +# Pride flag + +Puzzle from the [rendezvous with cassidoo](https://buttondown.email/cassidoo/archive/strive-to-do-better-but-dont-beat-yourself-up-for/) newsletter from June 28th, 2021. + +> Make a Pride flag! You decide how and with which languages/medium. + +Solution posted at https://gist.github.com/rust-play/180b75a22b96a5d92ed319c98d110a4e diff --git a/reorder/README.md b/reorder/README.md new file mode 100644 index 0000000..74cdb8a --- /dev/null +++ b/reorder/README.md @@ -0,0 +1,7 @@ +# Reorder + +Puzzle from the [rendezvous with cassidoo](https://buttondown.email/cassidoo/archive/reality-is-one-of-the-possibilities-i-cannot/) newsletter from October 18th, 2021. + +> Given an array of objects A, and an array of indexes B, reorder the objects in array A with the given indexes in array B. + +Solution posted at https://gist.github.com/zoeisnowooze/cb2f622431046c4dd126410f10023153 diff --git a/repeated-groups/README.md b/repeated-groups/README.md new file mode 100644 index 0000000..26cf755 --- /dev/null +++ b/repeated-groups/README.md @@ -0,0 +1,17 @@ +# Repeated groups + +Puzzle from the [rendezvous with cassidoo](https://buttondown.email/cassidoo/archive/like-what-you-do-and-then-you-will-do-your-best/) newsletter from February 27th, 2023. + +> Given a list of numbers, return all groups of repeating consecutive numbers. +> +> Examples: +> +> ```javascript +> > repeatedGroups([1, 2, 2, 4, 5]) +> [[2, 2]] +> +> > repeatedGroups([1, 1, 0, 0, 8, 4, 4, 4, 3, 2, 1, 9, 9]) +> [[1, 1], [0, 0], [4, 4, 4], [9, 9]] +> ``` + +Solution posted at https://strangeobject.space/@ooze/109937701330608625 diff --git a/roll-dice/README.md b/roll-dice/README.md new file mode 100644 index 0000000..d4cd793 --- /dev/null +++ b/roll-dice/README.md @@ -0,0 +1,19 @@ +# Roll dice + +Puzzle from the [rendezvous with cassidoo](https://buttondown.email/cassidoo/archive/3709/) newsletter of March 27th, 2023. + +> Given a string in dice notation, return a random integer you can get by rolling those dice. +> +> ```javascript +> > rollDice('4d4') // Four 4-sided dice +> > 13 +> +> > rollDice('3d20') // Three 20-sided dice +> > 28 +> +> > rollDice('1d8+2d10') // One 8-sided dice, and two 10-sided dice +> > 21 +> ``` + +Solution posted at https://strangeobject.space/@ooze/110098248197472738 +Alternate Rust solution at https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=8ab6422cecc9fc82a0e5017878d0b355 diff --git a/roll-dice/roll_dice.py b/roll-dice/roll_dice.py new file mode 100644 index 0000000..fff7f53 --- /dev/null +++ b/roll-dice/roll_dice.py @@ -0,0 +1,8 @@ +import random + + +def roll_dice(spec): + return sum( + sum(random.randint(1, int(a)) for _ in range(int(b))) if b else int(a) + for a, _, b in (s.partition("d") for s in spec.split("+")) + ) diff --git a/roll-dice/test_roll_dice.py b/roll-dice/test_roll_dice.py new file mode 100644 index 0000000..906922a --- /dev/null +++ b/roll-dice/test_roll_dice.py @@ -0,0 +1,28 @@ +import unittest + +from roll_dice import roll_dice + + +class TestRollDice(unittest.TestCase): + def test_constant(self): + self.assertEqual(roll_dice("1"), 1) + self.assertEqual(roll_dice("2"), 2) + + def test_sum(self): + self.assertEqual(roll_dice("1+2"), 3) + + def test_dice(self): + self.assertGreaterEqual(roll_dice("4d4"), 4) + self.assertLessEqual(roll_dice("4d4"), 16) + + def test_dice_plus_constant(self): + self.assertGreaterEqual(roll_dice("1d4+4"), 5) + self.assertLessEqual(roll_dice("1d4+4"), 8) + + def test_dice_plus_dice(self): + self.assertGreaterEqual(roll_dice("1d8+2d10"), 3) + self.assertLessEqual(roll_dice("1d8+2d10"), 28) + + +if __name__ == "__main__": + unittest.main() diff --git a/vertical-slashes/README.md b/vertical-slashes/README.md new file mode 100644 index 0000000..94f8c0e --- /dev/null +++ b/vertical-slashes/README.md @@ -0,0 +1,7 @@ +# Vertical slashes + +Puzzle from the [rendezvous with cassidoo](https://buttondown.email/cassidoo/archive/normal-is-not-something-to-aspire-to-its-4437/) from November 20th, 2023. + +> Write a function that takes a string of slashes (\ and /) and returns all of those slashes drawn downwards in a line connecting them. + +Solution posted at https://gist.github.com/zoeisnowooze/9d302565748fe8535a25727892533b22 diff --git a/vertical-slashes/verticalslashes.sh b/vertical-slashes/verticalslashes.sh new file mode 100755 index 0000000..0c1fbf9 --- /dev/null +++ b/vertical-slashes/verticalslashes.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +slashes=$(sed 's/\([\/\\]\)/\1/g' <<< "$1") +while [ -n "$slashes" ]; do + slash=$(cut -c1 <<< "$slashes") + case "$slash" in + " ") + slashes=$(cut -c2- <<< "$slashes"); + if [ "$(cut -c1 <<< "$slashes")" != "/" ]; then + echo -n "$slash" + fi + ;; + "/") + slashes=$(cut -c2- <<< "$slashes" | sed 's/ \([\\\/]\)/\1/g') + echo "$slash" + ;; + "\\") + slashes=$(cut -c2- <<< "$slashes" | sed 's/\([\\\/]\)/ \1/g') + echo "$slash" + ;; + esac +done +echo