aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad S Anwar <Mohammad.Anwar@yahoo.com>2021-01-10 07:21:57 +0000
committerGitHub <noreply@github.com>2021-01-10 07:21:57 +0000
commite41b1f3defd60cb045a1fccbbb4d108b0aedc581 (patch)
treebac11060f98c5a51a29c25abcbf473e33d798d6f
parentf53d8f703279156f2655a33fca007fbac19a8cd9 (diff)
parent7e468b1ececa0c32861a00a2e8bd1008cc2a9d00 (diff)
downloadperlweeklychallenge-club-e41b1f3defd60cb045a1fccbbb4d108b0aedc581.tar.gz
perlweeklychallenge-club-e41b1f3defd60cb045a1fccbbb4d108b0aedc581.tar.bz2
perlweeklychallenge-club-e41b1f3defd60cb045a1fccbbb4d108b0aedc581.zip
Merge pull request #3190 from pauloscustodio/094
Add Perl, C, C++, Basic and Forth solutions to challenge 094
-rw-r--r--challenge-094/paulo-custodio/basic/ch-1.bas181
-rw-r--r--challenge-094/paulo-custodio/basic/ch-2.bas121
-rw-r--r--challenge-094/paulo-custodio/c/ch-1.c168
-rw-r--r--challenge-094/paulo-custodio/c/ch-2.c200
-rw-r--r--challenge-094/paulo-custodio/cpp/ch-1.cpp71
-rw-r--r--challenge-094/paulo-custodio/cpp/ch-2.cpp156
-rw-r--r--challenge-094/paulo-custodio/forth/ch-1.fs257
-rw-r--r--challenge-094/paulo-custodio/forth/ch-2.fs178
-rw-r--r--challenge-094/paulo-custodio/perl/ch-1.pl51
-rw-r--r--challenge-094/paulo-custodio/perl/ch-2.pl93
-rw-r--r--challenge-094/paulo-custodio/python/ch-1.py48
-rw-r--r--challenge-094/paulo-custodio/python/ch-2.py96
-rw-r--r--challenge-094/paulo-custodio/test.pl92
13 files changed, 1712 insertions, 0 deletions
diff --git a/challenge-094/paulo-custodio/basic/ch-1.bas b/challenge-094/paulo-custodio/basic/ch-1.bas
new file mode 100644
index 0000000000..1b85e066dd
--- /dev/null
+++ b/challenge-094/paulo-custodio/basic/ch-1.bas
@@ -0,0 +1,181 @@
+' Challenge 094
+'
+' TASK #1 › Group Anagrams
+' Submitted by: Mohammad S Anwar
+' You are given an array of strings @S.
+'
+' Write a script to group Anagrams together in any random order.
+'
+' An Anagram is a word or phrase formed by rearranging the letters of a
+' different word or phrase, typically using all the original letters exactly
+' once.
+'
+' Example 1:
+' Input: ("opt", "bat", "saw", "tab", "pot", "top", "was")
+' Output: [ ("bat", "tab"),
+' ("saw", "was"),
+' ("top", "pot", "opt") ]
+' Example 2:
+' Input: ("x")
+' Output: [ ("x") ]
+
+' List of strings
+Type ListNodeType
+ value as String
+ nxt as ListNodeType Ptr
+End Type
+
+Type ListType
+ head as ListNodeType Ptr
+ tail as ListNodeType Ptr
+End Type
+
+
+' Map of keys to lists of strings
+Type MapNodeType
+ key as String
+ values as ListType
+ nxt as MapNodeType Ptr
+End Type
+
+Type MapType
+ head as MapNodeType Ptr
+ tail as MapNodeType Ptr
+End Type
+
+
+Sub list_push(Byref list as ListType, value as String)
+ Dim node as ListNodeType Ptr
+ node = Callocate(1, Sizeof(ListNodeType))
+ node->value = value
+ if list.head = 0 Then
+ list.head = node
+ list.tail = node
+ Else
+ list.tail->nxt = node
+ list.tail = node
+ End If
+End Sub
+
+Sub list_delete(Byref list as ListType)
+ Dim node as ListNodeType Ptr, nxt as ListNodeType Ptr
+ node = list.head
+ Do While node <> 0
+ nxt = node->nxt
+ Deallocate(node)
+ node = nxt
+ Loop
+End Sub
+
+Sub list_print(Byref list as ListType)
+ Dim node as ListNodeType Ptr
+ Print "(";
+ node = list.head
+ Do While node <> 0
+ If node <> list.head Then Print ", ";
+ Print """"; node->value; """";
+ node = node->nxt
+ Loop
+ Print ")";
+End Sub
+
+
+' add/find a key
+Function map_add_key(Byref map as MapType, key as String) as ListType Ptr
+ Dim node as MapNodeType Ptr
+ If map.head = 0 Then ' map empty
+ node = Callocate(1, Sizeof(MapNodeType))
+ map.head = node
+ map.tail = node
+ node->key = key
+ map_add_key = @node->values
+ Else
+ node = map.head
+ Do While node <> 0
+ If node->key = key Then ' found key
+ map_add_key = @node->values
+ Exit Function
+ End If
+ node = node->nxt
+ Loop
+
+ ' not found
+ node = Callocate(1, Sizeof(MapNodeType))
+ node->key = key
+ map.tail->nxt = node
+ map.tail = node
+ map_add_key = @node->values
+ End If
+End Function
+
+' add key/value
+Sub map_add_key_value(Byref map as MapType, key as String, value as String)
+ Dim list as ListType Ptr
+ list = map_add_key(map, key)
+ list_push(*list, value)
+End Sub
+
+Sub map_print(Byref map as MapType)
+ Dim node as MapNodeType Ptr
+ print "[ ";
+ node = map.head
+ Do While node <> 0
+ If node <> map.head Then Print ",":Print " ";
+ list_print(node->values)
+ node = node->nxt
+ Loop
+ Print " ]"
+End Sub
+
+Sub map_delete(Byref map as MapType)
+ Dim node as MapNodeType Ptr, nxt as MapNodeType Ptr
+ node = map.head
+ Do While node <> 0
+ nxt = node->nxt
+ list_delete(node->values)
+ Deallocate(node)
+ node = nxt
+ Loop
+End Sub
+
+
+' sort a string - selection sort
+Function sort_string(Byval s as String) as String
+ dim i as Integer, j as Integer, min_i as Integer
+ dim c as String
+
+ for i=0 to len(s)-1
+ min_i=i
+ for j=i+1 to len(s)
+ if Asc(Mid(s,j,1)) < Asc(Mid(s,min_i,1)) Then
+ min_i=j
+ End If
+ Next j
+
+ ' swap
+ c=Mid(s,i,1)
+ Mid(s,i,1)=Mid(s,min_i,1)
+ Mid(s,min_i,1)=c
+ next i
+ sort_string = s
+End Function
+
+
+' read strings from command line, build map
+Sub read_strings(Byref map as MapType)
+ Dim key as String, value as String
+ Dim i as Integer
+ i = 1
+ Do While Command(i) <> ""
+ value = Command(i)
+ key = sort_string(value)
+ map_add_key_value(map, key, value)
+ i = i+1
+ Loop
+End Sub
+
+' main
+Dim map as MapType
+read_strings(map)
+map_print(map)
+map_delete(map)
diff --git a/challenge-094/paulo-custodio/basic/ch-2.bas b/challenge-094/paulo-custodio/basic/ch-2.bas
new file mode 100644
index 0000000000..13d315b244
--- /dev/null
+++ b/challenge-094/paulo-custodio/basic/ch-2.bas
@@ -0,0 +1,121 @@
+' Challenge 094
+'
+' TASK #2 › Binary Tree to Linked List
+' Submitted by: Mohammad S Anwar
+' You are given a binary tree.
+'
+' Write a script to represent the given binary tree as an object and flatten
+' it to a linked list object. Finally print the linked list object.
+'
+' Example:
+' Input:
+'
+' 1
+' / \
+' 2 3
+' / \
+' 4 5
+' / \
+' 6 7
+'
+' Output:
+'
+' 1 -> 2 -> 4 -> 5 -> 6 -> 7 -> 3
+
+' input lines
+Dim Shared lines() as String
+
+' tree node
+Type NodeType
+ value as Integer
+ left_node as NodeType Ptr
+ right_node as NodeType Ptr
+End Type
+
+
+' read lines from stdin
+Sub read_lines()
+ Dim i as Integer
+ Open Cons for Input as #1
+ i = 0
+ Do Until Eof(1)
+ Redim Preserve lines(i) as String
+ Line Input #1, lines(i)
+ i = i+1
+ Loop
+ Close #1
+End Sub
+
+
+' parse lines, produce a tree
+Function parse_subtree(row as Integer, col as Integer) as NodeType Ptr
+ Dim node as NodeType Ptr
+
+ 'parse root
+ node = Callocate(1, Sizeof(NodeType))
+ If node=0 Then End -1
+ node->value = Val(Mid(lines(row), col, 1))
+
+ 'parse children
+ if row+2 <= UBound(lines) Then
+ If col-2 >= 1 And Mid(lines(row+1), col-1, 1) = "/" Then
+ node->left_node = parse_subtree(row+2, col-2)
+ End If
+ If col+2 <= Len(lines(row+2)) And Mid(lines(row+1), col+1, 1) = "\" Then
+ node->right_node = parse_subtree(row+2, col+2)
+ End If
+ End If
+ parse_subtree = node
+End Function
+
+Function parse_tree() as NodeType Ptr
+ Dim root as String, col as Integer
+ root = Trim(lines(0)) ' remove spaces, leave only root number
+ col = InStr(lines(0), root) ' find its column
+ parse_tree = parse_subtree(0, col)
+End Function
+
+Sub delete_tree(node as NodeType Ptr)
+ if node->left_node Then delete_tree(node->left_node)
+ if node->right_node Then delete_tree(node->right_node)
+ Deallocate(node)
+End Sub
+
+
+' flatten a tree
+Sub flatten_tree(root as NodeType Ptr)
+ Dim left_node as NodeType Ptr, right_node as NodeType Ptr, node as NodeType Ptr
+ If root <> 0 Then
+ left_node = root->left_node: flatten_tree(left_node)
+ right_node = root->right_node: flatten_tree(right_node)
+
+ root->left_node = 0
+ root->right_node = left_node
+
+ node = root
+ Do While node->right_node <> 0
+ node = node->right_node
+ Loop
+
+ node->right_node = right_node
+ End If
+End Sub
+
+Sub print_tree(root as NodeType Ptr)
+ Dim node as NodeType Ptr
+ node = root
+ Do While node <> 0
+ If node <> root Then Print " -> ";
+ Print Trim(Str(node->value));
+ node = node->right_node
+ Loop
+ Print
+End Sub
+
+' main
+Dim tree as NodeType Ptr
+read_lines
+tree = parse_tree
+flatten_tree tree
+print_tree tree
+delete_tree tree
diff --git a/challenge-094/paulo-custodio/c/ch-1.c b/challenge-094/paulo-custodio/c/ch-1.c
new file mode 100644
index 0000000000..13b70c9020
--- /dev/null
+++ b/challenge-094/paulo-custodio/c/ch-1.c
@@ -0,0 +1,168 @@
+/*
+Challenge 094
+
+TASK #1 › Group Anagrams
+Submitted by: Mohammad S Anwar
+You are given an array of strings @S.
+
+Write a script to group Anagrams together in any random order.
+
+An Anagram is a word or phrase formed by rearranging the letters of a
+different word or phrase, typically using all the original letters exactly
+once.
+
+Example 1:
+ Input: ("opt", "bat", "saw", "tab", "pot", "top", "was")
+ Output: [ ("bat", "tab"),
+ ("saw", "was"),
+ ("top", "pot", "opt") ]
+Example 2:
+ Input: ("x")
+ Output: [ ("x") ]
+*/
+
+#include <memory.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+// check memory allocation
+void* check_mem(void* p) {
+ if (!p) {
+ fputs("out of memory", stderr);
+ exit(EXIT_FAILURE);
+ }
+ return p;
+}
+
+
+// list of strings
+typedef struct ListNode {
+ char* str;
+ struct ListNode* next;
+} ListNode;
+
+typedef struct StrList {
+ ListNode* head, *tail;
+} StrList;
+
+StrList* strlist_alloc() {
+ return check_mem(calloc(1, sizeof(StrList)));
+}
+
+void strlist_free(StrList* list) {
+ if (list) {
+ ListNode* node = list->head;
+ while (node) {
+ ListNode* next = node->next;
+ free(node->str);
+ free(node);
+ node = next;
+ }
+ free(list);
+ }
+}
+
+void strlist_push(StrList* list, const char* str) {
+ ListNode* node = check_mem(calloc(1, sizeof(ListNode)));
+ node->str = check_mem(strdup(str));
+ if (!list->head) {
+ list->head = list->tail = node;
+ }
+ else {
+ list->tail->next = node;
+ list->tail = node;
+ }
+}
+
+void strlist_print(StrList* list) {
+ printf("(");
+ for (ListNode* node = list->head; node; node = node->next)
+ printf("\"%s\"%s", node->str, node->next ? ", " : "");
+ printf(")");
+}
+
+
+// map of strings to list of strings
+typedef struct TreeNode {
+ char* key;
+ struct TreeNode* left, *right;
+ StrList* strs;
+} TreeNode;
+
+TreeNode* tree_alloc() {
+ return NULL;
+}
+
+TreeNode* tree_add_key(TreeNode** proot, const char* key) {
+ if (*proot == NULL) {
+ TreeNode* node = check_mem(calloc(1, sizeof(TreeNode)));
+ node->key = check_mem(strdup(key));
+ node->strs = strlist_alloc();
+ *proot = node;
+ return node;
+ }
+ else {
+ TreeNode* node = *proot;
+ int cmp = strcmp(key, node->key);
+ if (cmp < 0)
+ return tree_add_key(&node->left, key);
+ else if (cmp > 0)
+ return tree_add_key(&node->right, key);
+ else
+ return node;
+ }
+}
+
+void tree_free(TreeNode* node) {
+ if (node) {
+ tree_free(node->left);
+ tree_free(node->right);
+ free(node->key);
+ strlist_free(node->strs);
+ free(node);
+ }
+}
+
+void tree_node_print(TreeNode* node, bool* is_first) {
+ if (node) {
+ tree_node_print(node->left, is_first);
+ if (!*is_first)
+ printf(",\n ");
+ strlist_print(node->strs);
+ *is_first = false;
+ tree_node_print(node->right, is_first);
+ }
+}
+
+void tree_print(TreeNode* tree) {
+ bool is_first = true;
+ printf("[ ");
+ tree_node_print(tree, &is_first);
+ printf(" ]\n");
+}
+
+int cmp_char(const void* a, const void* b) {
+ return *(const char*)a - *(const char*)b;
+}
+
+char* make_key(const char* str) {
+ char* key = check_mem(strdup(str));
+ qsort(key, strlen(key), 1, cmp_char);
+ return key;
+}
+
+int main(int argc, char* argv[]) {
+ TreeNode* tree = tree_alloc();
+
+ for (int i = 1; i < argc; i++) {
+ char* key = make_key(argv[i]);
+ TreeNode* node = tree_add_key(&tree, key);
+ strlist_push(node->strs, argv[i]);
+ free(key);
+ }
+
+ tree_print(tree);
+ tree_free(tree);
+}
diff --git a/challenge-094/paulo-custodio/c/ch-2.c b/challenge-094/paulo-custodio/c/ch-2.c
new file mode 100644
index 0000000000..90a3267260
--- /dev/null
+++ b/challenge-094/paulo-custodio/c/ch-2.c
@@ -0,0 +1,200 @@
+/*
+Challenge 094
+
+TASK #2 › Binary Tree to Linked List
+Submitted by: Mohammad S Anwar
+You are given a binary tree.
+
+Write a script to represent the given binary tree as an object and flatten
+it to a linked list object. Finally print the linked list object.
+
+Example:
+ Input:
+
+ 1
+ / \
+ 2 3
+ / \
+ 4 5
+ / \
+ 6 7
+
+ Output:
+
+ 1 -> 2 -> 4 -> 5 -> 6 -> 7 -> 3
+*/
+
+#include <assert.h>
+#include <ctype.h>
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MAXLINE 256
+
+// check memory allocation
+void* check_mem(void* p) {
+ if (!p) {
+ fputs("out of memory", stderr);
+ exit(EXIT_FAILURE);
+ }
+ return p;
+}
+
+// tree object
+typedef struct Tree {
+ int value;
+ struct Tree* left, * right;
+} Tree;
+
+// input image
+char** lines;
+size_t num_lines;
+
+
+// create and delete a tree
+Tree* tree_new() {
+ Tree* node = check_mem(calloc(1, sizeof(Tree)));
+ return node;
+}
+
+void tree_delete(Tree* node) {
+ if (node->left) tree_delete(node->left);
+ if (node->right) tree_delete(node->right);
+ free(node);
+}
+
+// read lines from stdin
+void lines_read() {
+ char line[MAXLINE];
+ while (fgets(line, sizeof(line), stdin)) {
+ lines = check_mem(realloc(lines, (num_lines + 1) * sizeof(char*)));
+ lines[num_lines] = check_mem(strdup(line));
+ num_lines++;
+ }
+}
+
+void lines_delete() {
+ if (lines) {
+ for (size_t i = 0; i < num_lines; i++)
+ free(lines[i]);
+ free(lines);
+ }
+}
+
+// parse the tree
+Tree* parse_subtree(int row, int col) {
+ // parse root
+ Tree* node = tree_new();
+ assert(isdigit(lines[row][col]));
+ node->value = lines[row][col] - '0';
+
+ // parse children
+ if (row + 2 < (int)num_lines) {
+ // parse left subtree
+ if (col - 2 >= 0 && lines[row + 1][col - 1] == '/')
+ node->left = parse_subtree(row + 2, col - 2);
+ // parse right subtree
+ if (col + 2 < (int)strlen(lines[row + 2]) && lines[row + 1][col + 1] == '\\')
+ node->right = parse_subtree(row + 2, col + 2);
+ }
+ return node;
+}
+
+Tree* parse_tree() {
+ assert(num_lines > 0);
+ char* p = strpbrk(lines[0], "0123456789");
+ assert(p);
+ int col = p - lines[0];
+ return parse_subtree(0, col);
+}
+
+/*
+// compute tree depth
+void subtree_depth(Tree* node, int cur_depth, int* pmax_depth) {
+ if (!node)
+ return;
+ if (node->left)
+ subtree_depth(node->left, cur_depth + 1, pmax_depth);
+ if (node->right)
+ subtree_depth(node->right, cur_depth + 1, pmax_depth);
+ if (cur_depth > *pmax_depth)
+ *pmax_depth = cur_depth;
+}
+
+int tree_depth(Tree* root) {
+ int max_depth = 0;
+ subtree_depth(root, 1, &max_depth);
+ return max_depth;
+}
+
+// print a tree
+void print_subtree(Tree* node, char* lines[], int row, int col) {
+ if (!node)
+ return;
+ lines[row][col] = '0' + node->value;
+ if (node->left) {
+ lines[row + 1][col - 1] = '/';
+ print_subtree(node->left, lines, row + 2, col - 2);
+ }
+ if (node->right) {
+ lines[row + 1][col + 1] = '\\';
+ print_subtree(node->right, lines, row + 2, col + 2);
+ }
+}
+
+void print_tree(Tree* root) {
+ // create canvas
+ int depth = tree_depth(root);
+ int num_lines = depth * 2;
+ int num_cols = depth * 5;
+ char** lines = check_mem(calloc(num_lines, sizeof(char*)));
+ for (int i = 0; i < num_lines; i++) {
+ lines[i] = check_mem(calloc(num_cols + 1, 1));
+ memset(lines[i], ' ', num_cols);
+ lines[i][num_cols] = '\0';
+ }
+
+ // draw tree
+ print_subtree(root, lines, 0, num_cols / 2);
+
+ // print tree
+ for (int i = 0; i < num_lines; i++)
+ printf("%s\n", lines[i]);
+
+ // delete canvas
+ for (int i = 0; i < num_lines; i++)
+ free(lines[i]);
+ free(lines);
+}
+*/
+
+// pre-order traversal, set left to NULL, move subtree to right
+Tree* flatten(Tree* root) {
+ if (!root) return root;
+ Tree* left = flatten(root->left);
+ Tree* right = flatten(root->right);
+
+ root->left = NULL;
+ root->right = left;
+
+ Tree* node = root;
+ while (node->right) // find right-most node
+ node = node->right;
+ node->right = right;
+
+ return root;
+}
+
+int main() {
+ lines_read();
+ Tree* tree = parse_tree();
+ flatten(tree);
+
+ for (Tree* node = tree; node; node = node->right)
+ printf("%d%s", node->value, node->right ? " -> " : "\n");
+
+ tree_delete(tree);
+ lines_delete();
+}
diff --git a/challenge-094/paulo-custodio/cpp/ch-1.cpp b/challenge-094/paulo-custodio/cpp/ch-1.cpp
new file mode 100644
index 0000000000..f3aa6ac58d
--- /dev/null
+++ b/challenge-094/paulo-custodio/cpp/ch-1.cpp
@@ -0,0 +1,71 @@
+/*
+Challenge 094
+
+TASK #1 › Group Anagrams
+Submitted by: Mohammad S Anwar
+You are given an array of strings @S.
+
+Write a script to group Anagrams together in any random order.
+
+An Anagram is a word or phrase formed by rearranging the letters of a
+different word or phrase, typically using all the original letters exactly
+once.
+
+Example 1:
+ Input: ("opt", "bat", "saw", "tab", "pot", "top", "was")
+ Output: [ ("bat", "tab"),
+ ("saw", "was"),
+ ("top", "pot", "opt") ]
+Example 2:
+ Input: ("x")
+ Output: [ ("x") ]
+*/
+
+#include <algorithm>
+#include <iostream>
+#include <list>
+#include <map>
+#include <string>
+
+std::string make_key(const std::string& str) {
+ std::string out{ str };
+ std::sort(out.begin(), out.end());
+ return out;
+}
+
+int main(int argc, char* argv[]) {
+ std::map<std::string, std::list<std::string>> map; // maps keys to lists of words
+
+ for (int i = 1; i < argc; i++) {
+ auto key = make_key(argv[i]);
+ auto found = map.find(key);
+ if (found == map.end()) { // not found, create new item
+ std::list<std::string> list;
+ list.push_back(argv[i]);
+ map[key] = list;
+ }
+ else { // append to existing item
+ found->second.push_back(argv[i]);
+ }
+ }
+
+ std::cout << "[ ";
+ bool first1 = true;
+ for (auto& it1 : map) {
+ if (!first1)
+ std::cout << "," << std::endl << " ";
+ first1 = false;
+
+ std::cout << "(";
+ bool first2 = true;
+ for (auto& it2 : it1.second) {
+ if (!first2)
+ std::cout << ", ";
+ first2 = false;
+
+ std::cout << "\"" << it2 << "\"";
+ }
+ std::cout << ")";
+ }
+ std::cout << " ]" << std::endl;
+}
diff --git a/challenge-094/paulo-custodio/cpp/ch-2.cpp b/challenge-094/paulo-custodio/cpp/ch-2.cpp
new file mode 100644
index 0000000000..6177ee537f
--- /dev/null
+++ b/challenge-094/paulo-custodio/cpp/ch-2.cpp
@@ -0,0 +1,156 @@
+/*
+Challenge 094
+
+TASK #2 › Binary Tree to Linked List
+Submitted by: Mohammad S Anwar
+You are given a binary tree.
+
+Write a script to represent the given binary tree as an object and flatten
+it to a linked list object. Finally print the linked list object.
+
+Example:
+ Input:
+
+ 1
+ / \
+ 2 3
+ / \
+ 4 5
+ / \
+ 6 7
+
+ Output:
+
+ 1 -> 2 -> 4 -> 5 -> 6 -> 7 -> 3
+*/
+
+#include <exception>
+#include <stdexcept>
+#include <iostream>
+#include <string>
+#include <vector>
+#include <cctype>
+
+// input image object
+class InputImage {
+public:
+ void append_line(const std::string& line);
+ void clear();
+ char ch(int row, int col) const;
+ int root_col() const;
+
+private:
+ std::vector<std::string> m_lines;
+};
+
+void InputImage::append_line(const std::string& line) {
+ m_lines.push_back(line);
+}
+
+void InputImage::clear() {
+ m_lines.clear();
+}
+
+char InputImage::ch(int row, int col) const {
+ // check if out of bounds
+ if (row < 0 || row >= static_cast<int>(m_lines.size()) ||
+ col < 0 || col >= static_cast<int>(m_lines[row].size()))
+ return ' ';
+ else
+ return m_lines[row][col];
+}
+
+int InputImage::root_col() const {
+ if (m_lines.empty())
+ throw std::invalid_argument("malformed image");
+ for (int col = 0; col < static_cast<int>(m_lines[0].size()); col++) {
+ if (isdigit(m_lines[0][col]))
+ return col;
+ }
+ throw std::invalid_argument("malformed image");
+}
+
+// tree object
+class Tree {
+public:
+ Tree(int value = 0);
+ ~Tree();
+
+ int value;
+ Tree* left, * right;
+
+ static Tree* parse(const InputImage& image);
+ static Tree* flatten(Tree* root);
+
+private:
+ static Tree* parse_subtree(const InputImage& image, int row, int col);
+};
+
+Tree::Tree(int value_)
+ : value(value_), left(nullptr), right(nullptr)
+{}
+
+Tree::~Tree() {
+ if (left) delete left;
+ if (right) delete right;
+}
+
+Tree* Tree::parse(const InputImage& image) {
+ int col = image.root_col();
+ return parse_subtree(image, 0, col);
+}
+
+Tree* Tree::parse_subtree(const InputImage& image, int row, int col) {
+ // parse root
+ int value = image.ch(row, col) - '0';
+ if (value < 0 || value>9)
+ throw std::invalid_argument("malformed image");
+ Tree* node = new Tree(value);
+
+ // parse left subtree
+ if (image.ch(row + 1, col - 1) == '/')
+ node->left = parse_subtree(image, row + 2, col - 2);
+ // parse right subtree
+ if (image.ch(row + 1, col + 1) == '\\')
+ node->right = parse_subtree(image, row + 2, col + 2);
+
+ return node;
+}
+
+Tree* Tree::flatten(Tree* root) {
+ if (!root) return root;
+ Tree* left = flatten(root->left);
+ Tree* right = flatten(root->right);
+
+ root->left = NULL;
+ root->right = left;
+
+ Tree* node = root;
+ while (node->right) // find right-most node
+ node = node->right;
+ node->right = right;
+
+ return root;
+}
+
+// read input from stdin
+void read_lines(InputImage& image) {
+ image.clear();
+ std::string line;
+ while (!std::getline(std::cin, line).eof())
+ image.append_line(line);
+}
+
+int main(int argc, char* argv[]) {
+ InputImage image;
+ read_lines(image);
+ Tree* tree = Tree::flatten(Tree::parse(image));
+
+ for (Tree* node = tree; node; node = node->right) {
+ if (node != tree)
+ std::cout << " -> ";
+ std::cout << node->value;
+ }
+ std::cout << std::endl;
+ delete tree;
+}
diff --git a/challenge-094/paulo-custodio/forth/ch-1.fs b/challenge-094/paulo-custodio/forth/ch-1.fs
new file mode 100644
index 0000000000..4f97a88525
--- /dev/null
+++ b/challenge-094/paulo-custodio/forth/ch-1.fs
@@ -0,0 +1,257 @@
+#! /usr/bin/env gforth
+
+\ Challenge 094
+\
+\ TASK #1 › Group Anagrams
+\ Submitted by: Mohammad S Anwar
+\ You are given an array of strings @S.
+\
+\ Write a script to group Anagrams together in any random order.
+\
+\ An Anagram is a word or phrase formed by rearranging the letters of a
+\ different word or phrase, typically using all the original letters exactly
+\ once.
+\
+\ Example 1:
+\ Input: ("opt", "bat", "saw", "tab", "pot", "top", "was")
+\ Output: [ ("bat", "tab"),
+\ ("saw", "was"),
+\ ("top", "pot", "opt") ]
+\ Example 2:
+\ Input: ("x")
+\ Output: [ ("x") ]
+
+\ -----------------------------------------------------------------------------
+\ counted strings
+
+\ compare two counted strings
+: cstr= ( c-addr1 c-addr2 -- f )
+ >R COUNT R> COUNT STR=
+;
+
+\ copy string as counted string to pad
+: str>pad ( addr len -- )
+ DUP PAD C!
+ PAD 1+ SWAP CMOVE
+;
+
+\ allot string as counted string
+: cstr, ( addr len -- )
+ DUP C, >R \ store length
+ HERE R@ CMOVE \ copy string
+ R> ALLOT \ advance HERE
+ ALIGN
+;
+
+\ -----------------------------------------------------------------------------
+\ Linked list of strings
+
+\ create a new string list
+: new_strlist ( -- list-addr )
+ HERE 0 , 0 ,
+;
+
+: strlist.head ( list-addr -- head-addr )
+;
+
+: strlist.tail ( list-addr -- tail-addr )
+ 1 CELLS +
+;
+
+\ create a new node for a string list
+: new_strnode ( addr len -- node-addr )
+ HERE >R ( R:node-addr )
+ 0 , \ store next pointer
+ cstr, \ store string
+ R> ( node-addr )
+;
+
+: strnode.next ( node-addr -- next-addr )
+;
+
+: strnode.cstring ( node-addr -- cstring-addr )
+ 1 CELLS +
+;
+
+\ push a string to the end of the list
+: strlist.push { addr len list-addr -- }
+ addr len new_strnode ( node-addr )
+ list-addr strlist.head @ 0= IF \ list is empty
+ DUP list-addr strlist.head !
+ list-addr strlist.tail !
+ ELSE
+ DUP
+ list-addr strlist.tail @ ( new-node last-node )
+ strnode.next ! \ store node in next of last node
+ list-addr strlist.tail ! \ point tail to node
+ THEN
+;
+
+: strlist.print-sep ( first -- first )
+ DUP IF
+ DROP 0
+ ELSE
+ ." , "
+ THEN
+;
+
+
+: strlist.print ( list-addr -- )
+ 1 SWAP ( first list-addr )
+ '(' EMIT
+ strlist.head @ ( first node-addr )
+ BEGIN DUP 0<> WHILE \ while pointer not null
+ SWAP strlist.print-sep SWAP
+ '"' EMIT
+ DUP strnode.cstring COUNT TYPE
+ '"' EMIT
+ strnode.next @
+ REPEAT
+ ')' EMIT
+ 2DROP
+;
+
+\ -----------------------------------------------------------------------------
+\ map of string to linked list of strings
+
+\ create new map
+: new_map ( -- map-addr )
+ HERE 0 , 0 ,
+;
+
+: map.head ( map-addr -- head-addr )
+;
+
+: map.tail ( map-addr -- tail-addr )
+ 1 CELLS +
+;
+
+\ create a new node for a map
+: new_mapnode ( addr len -- node-addr )
+ HERE >R ( R:node-addr )
+ 0 , \ store next pointer
+ new_strlist DROP \ store list of string values
+ cstr, \ store key string
+ R> ( node-addr )
+;
+
+: mapnode.next ( node-addr -- next-addr )
+;
+
+: mapnode.strlist ( node-addr -- strlist-addr )
+ 1 CELLS +
+;
+
+: mapnode.key ( node-addr -- cstring-addr )
+ 3 CELLS +
+;
+
+: map.add_first ( node-addr map-addr -- )
+ 2DUP
+ map.head !
+ map.tail !
+;
+
+: map.append { node-addr map-addr -- }
+ node-addr map-addr map.tail @ mapnode.next ! \ point next of last to node
+ node-addr map-addr map.tail ! \ point tail to node
+;
+
+: map.find_node ( map-addr -- node-addr|0 ) \ find node with key in PAD
+ map.head @ ( nope-addr )
+ BEGIN DUP 0<> WHILE
+ DUP mapnode.key PAD cstr= IF \ same key?
+ EXIT ( node-addr ) \ of found key
+ THEN
+ mapnode.next @ \ point to next
+ REPEAT
+ ( 0 ) \ entry not found
+;
+
+\ add/search a key to a map, return strlist
+: map.add_key { addr len map-addr -- node-strlist }
+ addr len str>pad \ save key in PAD
+ map-addr map.head @ 0= IF \ map is empty
+ PAD COUNT new_mapnode ( node-addr )
+ DUP map-addr map.add_first \ add first entry
+ mapnode.strlist ( node-strlist )
+ ELSE
+ map-addr map.find_node ( node-addr|0 )
+ ?DUP IF
+ mapnode.strlist ( node-strlist )
+ ELSE
+ PAD COUNT new_mapnode ( node-addr )
+ DUP map-addr map.append \ append node
+ mapnode.strlist ( node-strlist )
+ THEN
+ THEN
+;
+
+: map.print-sep ( first -- first )
+ DUP IF
+ DROP 0
+ ELSE
+ ',' EMIT CR 2 SPACES
+ THEN
+;
+
+: map.print ( map-addr -- )
+ 1 SWAP ( first map-addr )
+ ." [ "
+ map.head @ ( first node-addr )
+ BEGIN DUP 0<> WHILE
+ SWAP map.print-sep SWAP ( node-addr )<