diff options
| -rw-r--r-- | challenge-272/atschneid/README.md | 316 | ||||
| -rw-r--r-- | challenge-272/atschneid/blog.txt | 2 | ||||
| -rw-r--r-- | challenge-272/atschneid/c/ch-1.c | 36 | ||||
| -rw-r--r-- | challenge-272/atschneid/c/ch-2.c | 33 | ||||
| -rw-r--r-- | challenge-272/atschneid/c/makefile | 10 | ||||
| -rw-r--r-- | challenge-272/atschneid/perl/ch-1.pl | 23 | ||||
| -rw-r--r-- | challenge-272/atschneid/perl/ch-2.pl | 27 | ||||
| -rw-r--r-- | challenge-272/atschneid/prolog/ch-1.pro | 21 | ||||
| -rw-r--r-- | challenge-272/atschneid/prolog/ch-2.pro | 19 | ||||
| -rw-r--r-- | challenge-272/atschneid/prolog/makefile | 7 | ||||
| -rw-r--r-- | challenge-272/atschneid/racket/ch-1.rkt | 20 | ||||
| -rw-r--r-- | challenge-272/atschneid/racket/ch-2.rkt | 14 |
12 files changed, 444 insertions, 84 deletions
diff --git a/challenge-272/atschneid/README.md b/challenge-272/atschneid/README.md index e0a5c17bd2..80bbf700d9 100644 --- a/challenge-272/atschneid/README.md +++ b/challenge-272/atschneid/README.md @@ -1,133 +1,281 @@ -# Semi-Functional Solutions +# Defang and Sum-Abs-Char-Diffs -**Challenge 271 solutions in Perl by Andrew Schneider** +**Challenge 272 solutions by Andrew Schneider** -### Intro -This is my first Perl Weekly Challenge. I'm mostly a Python programmer in my day job so I like the chance to develop some other skills. I have a soft spot in my heart for Perl, let's say I'm a Perl slacker. I was surprised how functional this turned out - like functional programming. Also semi-surprised my solution functions. Har har. I have big plans for keeping up with the PWC using a randomly rotating selection of languages each week. I'm working on a script to select the language(s) I'll use -- stay tuned for that. +Being a stream of consciousness write up of some details of my code for [PWC 272](https://theweeklychallenge.org/blog/perl-weekly-challenge-272/) -### What did we learn? -It took me a little while to get the hang of multi-dimensional lists in Perl. Working on it for a little while eventually knocked something loose in the recesses of my brain, and now I feel sufficiently competent handling dimensions up to and including 3. As I said, I'm surprised with how functional these solutions turned out. It *could* be that is just the mindspace I'm in lately (see my Haskell contribution which I wrote after this one), or the problems just seemed suited to this. Anyway, functionally turned out to be a way to do it. +Let's get right to the problems -One gotcha I bumped into a few times is the difference between Perl versions. I started using 5.38, then 5.34, then back to 5.38, then 5.34 again, and finally 5.38. Along the way somewhere I picked up subroutine signatures[^1]. After much confusion and cursing I finally realized these weren't added until 5.36, right in the sweet spot between the versions I was trying. The lesson here I suppose is Read the Docs. +## Task 1: Defang IP Address +Submitted by: Mohammad Sajid Anwar -Now onto the code. - -## Task 1: Maximum Ones - -> You are given a m x n binary matrix.<br/> +> You are given a valid IPv4 address.<br/> > <br/> -> Write a script to return the row number containing maximum ones, in case of more than one rows then return smallest row number.<br/> +> Write a script to return the defanged version of the given IP address.<br/> > <br/> -> Example 1<br/> -> Input: $matrix = [ [0, 1],<br/> -> [1, 0],<br/> -> ]<br/> -> Output: 1<br/> +> A defanged IP address replaces every period “.” with “[.]".<br/> > <br/> -> Row 1 and Row 2 have the same number of ones, so return row 1.<br/> +> Example 1<br/> +> Input: $ip = "1.1.1.1"<br/> +> Output: "1[.]1[.]1[.]1"<br/> > Example 2<br/> -> Input: $matrix = [ [0, 0, 0],<br/> -> [1, 0, 1],<br/> -> ]<br/> -> Output: 2<br/> -> <br/> -> Row 2 has the maximum ones, so return row 2.<br/> -> Example 3<br/> -> Input: $matrix = [ [0, 0],<br/> -> [1, 1],<br/> -> [0, 0],<br/> -> ]<br/> -> Output: 2<br/> -> <br/> -> Row 2 have the maximum ones, so return row 2.<br/> +> Input: $ip = "255.101.1.0"<br/> +> Output: "255[.]101[.]1[.]0"<br/> -One thing that surprised me here, we want the 1 indexed row. For example, I would have expected the first solution to be 0, the zeroth row. But, I'll solve the problem I'm given. +### Perl -My solution here is to sum each row of the matrix. I do this using the old map reduce design +Really I think this problem wants a one-liner solution. Most of my chance to use Perl at work is writing one-liners like this guy -```perl - my @counts = map { reduce {$a + $b} 0, $_->@* } @matrix; +```bash +perl -lpe 's/\./[.]/g' +``` + +which converts exactly into a legal sed expression + +```bash +sed 's/\./[.]/g' ``` -Then find the first index of the max value over all the summed rows. I use a loop here for this (would recursion have been a more functional design?). I'm sure there is a better way to do this, but it works, and hey, this is my first PWC. +What we're doing here is a simple regex substitution on a period literal (gotta escape special characters) replacing with `[.]` + +But, it didn't just feel right to get away with this one so easily. Where's the boilerplate? What am I learning? So I coded up a fully respectable Perl version. + +The heart of the program is this little function ```perl - my $idx = 0; - for (0..scalar(@counts) - 1) { - if ($counts[$_] > $counts[$idx]) { - $idx = $_; +sub defang { + shift; + s/\./[.]/g; + return $_; +} +``` + +which is powered by much Perl magic. It expects a string variable, which gets `shift`ed into `$_`. Then substitution automagically happens on our `$_` variable by `s/\./[.]g;` (cf. `$_ =~ s/\./[.]/g;` for the same result with 90% less magic). Then pass back the substituted value in `$_`. I wondered if Perl would automagically return the special variable `$_` if the last line was simply `return;` and I learned it would not. So the final line is more sleight-of-hand than magic, but still. I often find it so much easier to use Perl's "do what I want" power on hidden magic variables that I contort my functions into horribly unnatural shapes just to get the magic to do what I need it to. Fortunately this particular function actually flows pretty naturally. + +### C + +Originally I had coded up my C implementation using `strtok_r`, but I realized it wasn't quite doing what I wanted. + +```c +void defang_first_try(char * input, char * output) { + char * token, * next_token; + + // blank the string contents in ouput + strcpy(output, ""); + token = strtok_r(input, ".", &next_token); + while (token) { + strcat(output, token); + printf(" %s\n", next_token); + token = strtok_r(NULL, ".", &next_token); + if (token) { + // if its not the last + strcat(output, "[.]"); } - } + } +} +``` + +It handles the example cases just fine, but based on a strict reading of the specification, every '.' should be replaced by '[.]', this implementation fails on basically all edge cases: leading, multiple, and trailing '.'s all get dropped. Although I'm really overthinking this here, because, again, on a strict reading of the instructions, we are given a *valid IP address* so it shouldn't really come up. Still, I thought about how to handle these cases in general, and decided 'every' means *every* (and outweighs *valid*) so if we were to get an input like "..." I'd expect the output to be "[.][.][.]". In keeping consistency across all of my implementations I decided on this one + +```c +void defang(char * input, char * output) { + size_t out_index = 0; + for (; *input != '\0'; input++) { + if (*input == '.') { + output[out_index++] = '['; + output[out_index++] = '.'; + output[out_index++] = ']'; + } + else { + output[out_index++] = *input; + } + } + output[out_index] = '\0'; +} ``` -And that's about it. I return that `$idx` value, then increment it (0 to 1 indexing) outside the function for no particularly good reason. +Here I'm crawling along the string one character at a time. If the char is `'.'` then add the chars `'[', '.', ']'` to the output string, otherwise just add the char itself. Interesting that my crude solution here is about as long as the one using `strtok`. If this problem had been *slightly* more complicated I might have had to use a library. -## Task 2: Sort by 1 bits +### Prolog -> You are give an array of integers, @ints.A<br/> +Next up, Prolog. Getting anything done in Prolog is always a trip for me. It takes a little while to adjust, in particular, I always forget I have to pass the output variable to the function. With Prolog, at very high level, you're not really saying "compute this function and store the return value in X" as much as "give me an X that is a solution to this function." What's really cool is that often you can flip that to be "here is an X that is the solution to this function, give its input Y that yields X" or something like that. Besides all that, the syntax turns out to be very similar to a functional language like Haskell or Lisp. Anyway, I digress. + +I decided to write this in a way that could be run using GNU Prolog. I don't remember why I decided that, maybe I wanted a challenge. Because once I started running into issues and started Googling ([DuckDuckGoing](https://duckduckgo.com) really) for answers I got a lot of results telling me how to do the thing I wanted very easily in SWI Prolog, which is a much more fully-featured, batteries included Prolog implementation. Handling strings is not easy to do in Prolog in general, but SWI has added a lot of functionality around this. If my understanding is correct, in Prolog a string is just a list of chars, except that it's not. For instance, you can't pattern match on it. But if you print a string you get a list of char codes, so it's kind of a lose-lose. + +The solution, or rather *a* solution, or better still *my* solution is to convert strings to atoms. Prolog loves atoms and there are functions to convert a list of chars into an atom, and by the Prolog reflexive property, vice versa. Printing an atom gives its name as you would expect, so that is what I use for output too. So in my roundabout Prolog solution, I start by converting a string to a list of chars + +```prolog +str_to_chars(S, Cs) :- atom_codes(X, S), atom_chars(X, Cs). +``` + +If we initialize this function as `str_to_chars("hello", Cs).` it first looks for a solution to `atom_codes(X, "hello")` which is, it looks for an atom whose characters match the list of char codes (recall the string is represented as a list of char codes) of "hello" (explicitly `[104,101,108,108,111]`). This is exactly the atom `hello` which is bound to the variable `X`. Next it tries `atom_chars(X, Cs)` which is now `atom_chars(hello, Cs)` which attempts to find a list of chars (not char codes here) which make up the characters of `hello`, obviously giving `['h', 'e', 'l', 'l', 'o']` which gets bound to the variable `Cs`. Phew. There's got to be a better way to do this, but this works. + +Now that we have a list of chars, the rest is pretty easy. The easy part was the hard part. What we'll do is recur through the list of chars. If the list is empty, return an empty list. If the first char is `'.'` return the list `['[', '.', ']']` appended to the defanged list minus its head, and otherwise append the head to the defanged list minus its head. Like so + +```prolog +defang_chars([], []). +defang_chars(['.'|Xs], ['[', '.', ']'|Y]) :- defang_chars(Xs, Y), !. +defang_chars([X|Xs], [X|Y]) :- defang_chars(Xs, Y). +``` + +You know I really abused terminology there. Prolog doesn't return anything! It just shows how hard it is to get my mind into logic programming mode. Really it's (constructive) matching. One thing to point out is the cut `!` operator in line 2. What I want here is that if we match a `'.'` then commit to it. Don't backtrack and end up on line 3, since that won't give us the correct output. + +### Racket + +I'll mention briefly my Racket solution. After struggling through my Prolog implementation, this one was a breeze. Racket, and Scheme more broadly, includes lots of batteries, like a function to convert a string to a list of chars! The heart of the logic is basically the same as for Prolog. Given a list of chars, figure out what to do with the head of the list, and append to the operation on the tail. + +```racket +(define (defang-list s) + (let loop ([s s]) + (if (empty? s) + '() + (let ([first (car s)] [rest (cdr s)]) + (case first + [(#\.) (append '(#\[ #\. #\]) (loop rest))] + [else (cons first (loop rest))]))))) +``` + +One cool thing I dug up was `raco fmt` which is a code formatter for Racket. I used to think, "I'm a freewheelin' guy, don't fence me in, I'll format my code however I feel," but now I know that guy was a jerk! Find a style and stick with it, it will make your life easier. It doesn't matter so much what format you use as that you use a format. I read that somewhere once, and now I agree. + +### *** + +Amusing side note, I had mentally converted 'defang' to 'defrang', and coded up all my solutions using 'defrang' in the function names somewhere, then had to do a substitution to get things back to normal. Maybe that's an idea for a future PWC - fix all the function names in some C code or something like that. Also, defrang ... I like that word. I'll have to remember to try to use that somewhere. + + +## Task 2: String Score +Submitted by: Mohammad Sajid Anwar + +> You are given a string, $str.<br/> > <br/> -> Write a script to sort the integers in ascending order by the number of 1 bits in their binary representation. In case more than one integers have the same number of 1 bits then sort them in ascending order.<br/> +> Write a script to return the score of the given string.<br/> +> <br/> +> The score of a string is defined as the sum of the absolute difference between the ASCII values of adjacent characters.<br/> > <br/> > Example 1<br/> -> Input: @ints = (0, 1, 2, 3, 4, 5, 6, 7, 8)<br/> -> Output: (0, 1, 2, 4, 8, 3, 5, 6, 7)<br/> +> Input: $str = "hello"<br/> +> Output: 13<br/> +> <br/> +> ASCII values of characters:<br/> +> h = 104<br/> +> e = 101<br/> +> l = 108<br/> +> l = 108<br/> +> o = 111<br/> > <br/> -> 0 = 0 one bits<br/> -> 1 = 1 one bits<br/> -> 2 = 1 one bits<br/> -> 4 = 1 one bits<br/> -> 8 = 1 one bits<br/> -> 3 = 2 one bits<br/> -> 5 = 2 one bits<br/> -> 6 = 2 one bits<br/> -> 7 = 3 one bits<br/> +> Score => |104 - 101| + |101 - 108| + |108 - 108| + |108 - 111|<br/> +> => 3 + 7 + 0 + 3<br/> +> => 13<br/> > Example 2<br/> -> Input: @ints = (1024, 512, 256, 128, 64)<br/> -> Output: (64, 128, 256, 512, 1024)<br/> +> Input: "perl"<br/> +> Output: 30<br/> +> <br/> +> ASCII values of characters:<br/> +> p = 112<br/> +> e = 101<br/> +> r = 114<br/> +> l = 108<br/> +> <br/> +> Score => |112 - 101| + |101 - 114| + |114 - 108|<br/> +> => 11 + 13 + 6<br/> +> => 30<br/> +> Example 3<br/> +> Input: "raku"<br/> +> Output: 37<br/> +> <br/> +> ASCII values of characters:<br/> +> r = 114<br/> +> a = 97<br/> +> k = 107<br/> +> u = 117<br/> > <br/> -> All integers in the given array have one 1-bits, so just sort them in ascending order.<br/> +> Score => |114 - 97| + |97 - 107| + |107 - 117|<br/> +> => 17 + 10 + 10<br/> +> => 37<br/> -At first I thought I was going to end up reusing some pieces of my solution to Task 1 for this, but it turned out to be just different enough that I didn't think it was worth it. +What I like most about this challenge is it finally gives us a way to directly compare programming languages. Now if someone asks if Raku is better than Perl I can say 37 > 30 so yes! -So first we need to convert our integers to some kind of binary representation. In Perl it makes a lot if sense to go to strings, since converting between strings that look like numbers and numbers that look like strings is covered in minute 2 of the 15 Minutes to Perl crash course. +This is a cool one. I could imagine some variation of this being used to encrypt messages somehow. -```perl - my @bins = map { sprintf "%b", $_ } @input; -``` +Let's see some code + +### Perl -Next we need to sum them up. (Is there a better way to do this? I seem to be repeating this pattern alot.) +Here is the Perl function that does basically all the work. ```perl - my @bin_sums = map { reduce { $a + $b } 0, split(//, $_) } @bins; +sub sum_char_abs_diff ($s) { + my @slist = map { ord } split '', $s; + my $sum = 0; + for my $idx ( 1..scalar(@slist) - 1 ) { + $sum += abs( $slist[$idx] - $slist[$idx-1] ); + } + return $sum; +} ``` -Next I make a list of tuples (pairs) of ( binary sum, integer value ), which I can sort further on. Eep! It's another loop. I'm really harming my functional credentials. +It takes a string, splits it on `''` which gives a list of characters. Then we map each value in that list of chars to its ascii value using `ord`. Next we initialize our sum value to 0. The for loop runs from index 1 until the end of the char-int list. This has the nice effect of handling strings of size 0 and size 1, the loop will never run and the value of 0 will be returned, which is how I would define these edge cases. Within the loop we add to the sum the absolute value of the difference of the element at the index and the element before it. That's a lot of words but it should be pretty clear by looking at the code. -```perl - my @tuple_list = (); - for (0..scalar(@bin_sums) - 1) { - push @tuple_list, ([ $bin_sums[$_], $input[$_]]); +It looks like a pretty clean solution to me this time. I wonder if I could one-line it. + +### C + +The C code is very similar to the Perl solution + +```c +int sum_abs_char_diffs(const char * s) { + const size_t s_len = strlen(s); + + int abs_diff, sum = 0; + for (int i=1; i < s_len; i++) { + abs_diff = abs(s[i] - s[i-1]); + sum += abs_diff; } + return sum; +} ``` -Then I sort this super-list, first on the 0th index, then on the 1st +One thing to point out here is that it plays to C's strengths, a char is basically an int! I though about trying some implicit casting in Perl, but it is too eager to do some `atoi` magic, in C we can simply do the arithmetic on the chars and the results come out right. -```perl - my @sorted_list = sort { ${$a}[0] <=> ${$b}[0] || ${$a}[1] <=> ${$b}[1] } @tuple_list; +### Prolog + +Basically everything happens in this function + +```prolog +sum_char_diffs([], 0). +sum_char_diffs([_], 0). +sum_char_diffs([A, B|Xs], S) :- + A > B, + sum_char_diffs([B|Xs], S2), S is S2 + A - B. +sum_char_diffs([A, B|Xs], S) :- + B >= A, + sum_char_diffs([B|Xs], S2), S is S2 + B - A. ``` -Then map back just to a simple list of integers +Here we match explicitly on an empty string or a string of length 1 and bind the value 0, otherwise we bind the sum of the difference of the first two elements plus the value from the same function called recursively on the list minus its head. Many words, but hopefully the code makes enough sense on its own. -```perl - map { ${$_}[1] } @sorted_list; +The trickiest bit here is that I'm not sure if there's an absolute value function so I just treat `A > B` and `B >= A` separately. + +The fact that Prolog thinks of strings as a list of char codes works well for me here, no conversion necessary! Take that Prolog! + +### Racket + +Despite the looks of this one it was easy again to write. + +```racket +(define (sum-abs-char-diffs s) + (let* ([char-list (string->list s)] [num-list (map char->integer char-list)]) + (let loop ([num-list num-list] [diff-sum 0]) + (if (> 2 (length num-list)) + diff-sum + (loop (cdr num-list) (+ diff-sum (abs (- (car num-list) (cadr num-list))))))))) ``` -I think that wraps it up. +The logic here is basically the same as for Prolog, in a functional form (returns a value). -## Post script +As far as formatting, I wasn't sure what to do about the stack of closing parens that built up at the end, but `raco fmt` just bunched them all together on the last line, so I'll accept that. -There wasn't a ton to figure out here, mostly it was an engineering challenge (how do I do *X*?). Plus some self inflicted versioning pain. Really with the amount of functional style stuff going in here, I wonder if I could one-line these. Hmm... Future work I suppose. +### Conclusion -Thanks for the challenge! +Ok. This concludes my long, rambling notes on my various solutions to this week's challenges. I'm looking forward to seeing what comes up next week, and maybe soon I'll send in some of the challenge ideas I've been thinking up. -[^1]: Really? Only just in 5.36? +See you next week. diff --git a/challenge-272/atschneid/blog.txt b/challenge-272/atschneid/blog.txt new file mode 100644 index 0000000000..ee6a47af39 --- /dev/null +++ b/challenge-272/atschneid/blog.txt @@ -0,0 +1,2 @@ +https://github.com/atschneid/perlweeklychallenge-club/blob/master/challenge-272/atschneid/README.md + diff --git a/challenge-272/atschneid/c/ch-1.c b/challenge-272/atschneid/c/ch-1.c new file mode 100644 index 0000000000..849874dcef --- /dev/null +++ b/challenge-272/atschneid/c/ch-1.c @@ -0,0 +1,36 @@ +# include <stdio.h> +# include <string.h> // strcpy, strcat, strtok_r + + +void defang(char * input, char * output) { + size_t out_index = 0; + for (; *input != '\0'; input++) { + if (*input == '.') { + output[out_index++] = '['; + output[out_index++] = '.'; + output[out_index++] = ']'; + } + else { + output[out_index++] = *input; + } + } + output[out_index] = '\0'; +} + + +int main() { + const size_t strmax = 20; + const size_t num_strings = 2; + char inputs[num_strings][strmax] = { + "1.1.1.1", + "255.101.1.0" + }; + + // max size if all chars are '.' + char outputs[num_strings][strmax * 3]; + for (int i=0; i < num_strings; i++) { + printf("%s => ", inputs[i]); + defang(inputs[i], outputs[i]); + printf("%s\n", outputs[i]); + } +} diff --git a/challenge-272/atschneid/c/ch-2.c b/challenge-272/atschneid/c/ch-2.c new file mode 100644 index 0000000000..6bc8a4a847 --- /dev/null +++ b/challenge-272/atschneid/c/ch-2.c @@ -0,0 +1,33 @@ +# include <stdio.h> +# include <string.h> // strlen +# include <stdlib.h> // abs + +int sum_abs_char_diffs(const char * s) { + const size_t s_len = strlen(s); + + int abs_diff, sum = 0; + for (int i=1; i < s_len; i++) { + abs_diff = abs(s[i] - s[i-1]); + sum += abs_diff; + } + return sum; +} + + +int main() { + char * inputs[] = { + "hello", + "perl", + "raku", + "c" + }; + const size_t num_strings = 4; + + for (int i=0; i < num_strings; i++) { + printf("input : %s, sum : %d\n", + inputs[i], + sum_abs_char_diffs(inputs[i])); + } +} + + diff --git a/challenge-272/atschneid/c/makefile b/challenge-272/atschneid/c/makefile new file mode 100644 index 0000000000..f22871e256 --- /dev/null +++ b/challenge-272/atschneid/c/makefile @@ -0,0 +1,10 @@ +CFLAGS := -g -Wall -std=c11 -O3 + +all: ch-1 ch-2 + +ch-1: ch-1.c + cc $(CFLAGS) ch-1.c -o ch-1 + +ch-2: ch-2.c + cc $(CFLAGS) ch-2.c -o ch-2 + diff --git a/challenge-272/atschneid/perl/ch-1.pl b/challenge-272/atschneid/perl/ch-1.pl new file mode 100644 index 0000000000..b42f7e2403 --- /dev/null +++ b/challenge-272/atschneid/perl/ch-1.pl @@ -0,0 +1,23 @@ +use strict; +use warnings; + +use v5.38; + +my @test_inputs = @ARGV; +if (scalar @ARGV == 0) { + @test_inputs = ( + "1.1.1.1", + "255.101.1.0" + ); +} + +for (@test_inputs) { + printf; + say " => " . defang($_); +} + +sub defang { + shift; + s/\./[.]/g; + return $_; +} diff --git a/challenge-272/atschneid/perl/ch-2.pl b/challenge-272/atschneid/perl/ch-2.pl new file mode 100644 index 0000000000..d36b2a6527 --- /dev/null +++ b/challenge-272/atschneid/perl/ch-2.pl @@ -0,0 +1,27 @@ +use strict; +use warnings; + +use v5.38; + +my @test_inputs = @ARGV; +if (scalar @ARGV == 0) { + @test_inputs = ( + "hello", + "perl", + "raku" + ); +} + +for (@test_inputs) { + printf; + say " : " . sum_char_abs_diff($_); +} + +sub sum_char_abs_diff ($s) { + my @slist = map { ord } split '', $s; + my $sum = 0; + for my $idx ( 1..scalar(@slist) - 1 ) { + $sum += abs( $slist[$idx] - $slist[$idx-1] ); + } + return $sum; +} diff --git a/challenge-272/atschneid/prolog/ch-1.pro b/challenge-272/atschneid/prolog/ch-1.pro new file mode 100644 index 0000000000..85758209de --- /dev/null +++ b/challenge-272/atschneid/prolog/ch-1.pro @@ -0,0 +1,21 @@ +:- initialization(main). + +str_to_chars(S, Cs) :- atom_codes(X, S), atom_chars(X, Cs). + +defang_chars([], []). +defang_chars(['.'|Xs], ['[', '.', ']'|Y]) :- defang_chars(Xs, Y), !. +defang_chars([X|Xs], [X|Y]) :- defang_chars(Xs, Y). + +defang_string(X, Y) :- + str_to_chars(X, Cs), + defang_chars(Cs, Dcs), + atom_chars(Y, Dcs). + +output_helper(String) :- + atom_codes(I0, String), print(I0), + write(' => '), + defang_string(String, X0), write(X0), nl. + +main:- + maplist(output_helper, ["1.1.1.1", "255.101.1.0"]), + halt. diff --git a/challenge-272/atschneid/prolog/ch-2.pro b/challenge-272/atschneid/prolog/ch-2.pro new file mode 100644 index 0000000000..99820e74b0 --- /dev/null +++ b/challenge-272/atschneid/prolog/ch-2.pro @@ -0,0 +1,19 @@ +:- initialization(main). + +sum_char_diffs([], 0). +sum_char_diffs([_], 0). +sum_char_diffs([A, B|Xs], S) :- + A > B, + sum_char_diffs([B|Xs], S2), S is S2 + A - B. +sum_char_diffs([A, B|Xs], S) :- + B >= A, + sum_char_diffs([B|Xs], S2), S is S2 + B - A. + +output_helper(Word) :- + atom_codes(I0, Word), print(I0), + write(' :: '), + sum_char_diffs(Word, X0), write(X0), nl. + +main:- + maplist(output_helper, ["hello", "perl", "raku", "prolog"]), + halt. diff --git a/challenge-272/atschneid/prolog/makefile b/challenge-272/atschneid/prolog/makefile new file mode 100644 index 0000000000..eb4ce6b68a --- /dev/null +++ b/challenge-272/atschneid/prolog/makefile @@ -0,0 +1,7 @@ +all: ch-1 ch-2 + +ch-1: ch-1.pro + gplc ch-1.pro + +ch-2: ch-2.pro + gplc ch-2.pro diff --git a/challenge-272/atschneid/racket/ch-1.rkt b/challenge-272/atschneid/racket/ch-1.rkt new file mode 100644 index 0000000000..fe0ad6dd1c --- /dev/null +++ b/challenge-272/atschneid/racket/ch-1.rkt @@ -0,0 +1,20 @@ +#lang racket + +(define inputs '("1.1.1.1" "255.101.1.0")) + +(define (defang-list s) + (let loop ([s s]) + (if (empty? s) + '() + (let ([first (car s)] [rest (cdr s)]) + (case first + [(#\.) (append '(#\[ #\. #\]) (loop rest))] + [else (cons first (loop rest))]))))) + +(define (defang s) + (list->string (defang-list (string->list s)))) + +(let ([defanged (map defang inputs)]) + (map (lambda [c n] (printf "~a => ~a\n" c n)) inputs defanged) + #t) + diff --git a/challenge-272/atschneid/racket/ch-2.rkt b/challenge-272/atschneid/racket/ch-2.rkt new file mode 100644 index 0000000000..5c7d6b97f7 --- /dev/null +++ b/challenge-272/atschneid/racket/ch-2.rkt @@ -0,0 +1,14 @@ +#lang racket + +(define inputs '("hello" "perl" "raku" "lisp" "scheme" "racket")) + +(define (sum-abs-char-diffs s) + (let* ([char-list (string->list s)] [num-list (map char->integer char-list)]) + (let loop ([num-list num-list] [diff-sum 0]) + (if (> 2 (length num-list)) + diff-sum + (loop (cdr num-list) (+ diff-sum (abs (- (car num-list) (cadr num-list))))))))) + +(let ([diffs (map sum-abs-char-diffs inputs)]) + (map (lambda [c n] (printf "~a : ~a\n" c n)) inputs diffs) + #t) |
