{"id":21401004,"url":"https://github.com/unusualcodeorg/clab","last_synced_at":"2025-04-16T02:38:31.176Z","repository":{"id":252062906,"uuid":"832855855","full_name":"unusualcodeorg/clab","owner":"unusualcodeorg","description":"clab - Creative Programming Solutions using C - Programming is enjoyable when applied to solve interesting problems (may not be directly used in general day-to-day professional work). The learning and knowledge acquired in the process make a better programmer.","archived":false,"fork":false,"pushed_at":"2024-08-07T20:29:54.000Z","size":316,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-29T04:12:56.241Z","etag":null,"topics":["c","coding-challenge","consumer-producer","cpp","graph","hashmap","linkedlist","maze-algorithms","programming","pthreads","puzzles","queue","stack","thread-pool","travelling-salesman-problem","tree"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/unusualcodeorg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-07-23T21:28:51.000Z","updated_at":"2025-02-17T10:14:55.000Z","dependencies_parsed_at":"2024-08-07T14:01:48.568Z","dependency_job_id":"1d6eeba0-e3d5-4758-96c6-68c91ddfbb51","html_url":"https://github.com/unusualcodeorg/clab","commit_stats":null,"previous_names":["unusualcodeorg/clab"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unusualcodeorg%2Fclab","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unusualcodeorg%2Fclab/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unusualcodeorg%2Fclab/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unusualcodeorg%2Fclab/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/unusualcodeorg","download_url":"https://codeload.github.com/unusualcodeorg/clab/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249185148,"owners_count":21226522,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","coding-challenge","consumer-producer","cpp","graph","hashmap","linkedlist","maze-algorithms","programming","pthreads","puzzles","queue","stack","thread-pool","travelling-salesman-problem","tree"],"created_at":"2024-11-22T15:25:22.591Z","updated_at":"2025-04-16T02:38:31.145Z","avatar_url":"https://github.com/unusualcodeorg.png","language":"C","readme":"# clab: Creative Programming Solutions\n![Banner](.extra/docs/clab-banner.png)\n\n# About the project\nclab project aims to provide creative solutions to interesting programming problems. \n\nC language has been chosen so that the project can develop solutions from scratch and in the process we will build the necessary data structures and algorithms. \n\nAlso, a solution is very insightful when memory is at center stage. We get closer to the actual hardware and the operating system, getting the maximum performance.\n\nProgramming is enjoyable when applied to solve interesting problems (may not be directly used in general day-to-day professional work). The learning and knowledge acquired in the process make a better programmer.\n\n## An Interesting Problem - Orienteering Challenge\nGiven a maze of m x n size\n```\n# boundary\n. open path\n@ checkpoint\nS source\nG destination\n```\n\nDevelop a program to find the shortest path from 'S' to 'G', visiting all the '@'s.\n\nExample: 7 x 9 maze\n```\n#########\n#....#.@#\n#.@...G.#\n#.#.....#\n#.##@####\n#....S..#\n#########\n```\n\nSolution:\n```\nStep 1:     Step 2:      Step 3:      Step 4:\n#########   #########    #########    #########\n#    #  #   #    #  #    #    #.1#    #    #.1#\n#       #   # 2..   #    # 2...G #    #     G #\n# #     #   # # .   #    # #     #    # #     #\n# ##3####   # ##3####    # ## ####    # ## ####\n#   .S  #   #       #    #       #    #       #\n#########   #########    #########    #########\n\nMaze: shortest travel distance 14\nTime taken: 0.000932 sec\n```\n\nBackground:\n\u003e I got this problem statement in my college placement, but I was not able to solve it in the given deadline. Later in the holidays I went home and was able to solve it ([solution link](https://github.com/janishar/orienteering-problem)), but with the limited knowledge it was difficult to optimize it. Now, after a decade its exciting to revisit the problem and take it as an opportunity to experiment with many other programming concepts.\n\n### Solution pointers\nThis project develops as an experiement - We play with one part at a time and build it as a general solution through investigation.\n\n- If there are N checkpoints the total possible path is N!. Factorial N gets very large with increase in N. For example: factorial 12 is 479,001,600. \n- To process such a large combination, we have to reduce memory space through better algorithms.\n- We will use threads to do concurrent processing.\n- Many data-structures will play a role in the solution: Graph, Stack, Queue, HashMap, LinkedList, Array, BufferQueue, Tree (for fun)\n- The Maze conversion into a Graph and printing solution is also a good problem statement in itself.\n- All the data-structures need to be thread safe, since we are using concurrent processing.\n\nNote:\n\u003e We will not use recursion, since the function stack size is limited, and easily throws stackoverflow error. We will use Stack data-structure for computation in suce cases.\n\nC does not have generics, but it has void pointer to reference any data type. We will use this to hold data in our data-structures. In this case we will have to pass function pointers to free those data, when we destroy our data-structure.\n\n### Important Data-Structures and Algorithms\n\n---\n\n#### Helper functions:\n```c\n// src/dslib/destroy.h\ntypedef void (*FreeDataFunc)(void *);\n\n// src/dslib/destroy.c\nvoid free_data_func(void *data) {\n  if (data != NULL) free(data);\n}\n\n// src/dslib/datastr.h\ntypedef char *(*DataToString)(void *);\n\n// src/dslib/datastr.c\nchar *char_data_to_string(void *arg) {\n  char data = *(char *)arg;\n  char *buffer = malloc(50);\n  snprintf(buffer, 50, \"%c\", data);\n  return buffer;\n}\n```\n\n---\n\n#### Stack - `src/dslib/stack.h`\n```c\ntypedef struct StackNode {\n  void *data;\n  struct StackNode *next;\n} StackNode;\n\ntypedef struct {\n  StackNode *top;\n  size_t size;\n  pthread_rwlock_t rwlock;\n} Stack;\n\nStack *stack_create(void);\nvoid stack_push(Stack *stack, void *data);\nvoid *stack_pop(Stack *stack, FreeDataFunc freedatafunc);\nvoid *stack_peek(Stack *stack);\nvoid *stack_get(Stack *stack, size_t position);\nvoid stack_print(Stack *stack, DataToString tostring);\nvoid stack_destroy(Stack *stack, FreeDataFunc freedatafunc);\n```\n\nStack is a simple data-structure, we push items on the top and also remove items from the top. The item which goes in first comes out at last. Stack help in DFS (depth first search) in trees and graphs, i.e. we move to the last node first and then move to the top.\n\nIn recursion case, it help to go to the base condition and then accumulate the result moving up.\n\n---\n\n#### Queue - `src/dslib/queue.h`\n\n```c\ntypedef struct QueueNode {\n  void *data;\n  struct QueueNode *next;\n} QueueNode;\n\ntypedef struct {\n  QueueNode *start;\n  QueueNode *end;\n  size_t size;\n  pthread_rwlock_t rwlock;\n} Queue;\n\nQueue *queue_create(void);\nvoid queue_enqueue(Queue *queue, void *data);\nvoid *queue_dequeue(Queue *queue, FreeDataFunc freedatafunc);\nvoid *queue_peek(Queue *queue);\nvoid *queue_get(Queue *queue, size_t position);\nvoid queue_print(Queue *queue, DataToString tostring);\nvoid queue_destroy(Queue *queue, FreeDataFunc freedatafunc);\n\n```\nQueue stores the data at the end and gives from the start. The items which goes in first comes out first. This helps in BFS (breadth first search) in trees and graphs. We visit the nearest nodes first before moving to the farthest nodes, opposite to the Stack.\n\n---\n\n#### HashMap - `src/dslib/hashmap.h`\n\n```c\ntypedef struct HashNode {\n  char *key;\n  void *value;\n  struct HashNode *next;  // seperate chining in linked list\n} HashNode;\n\ntypedef struct {\n  size_t size;\n  HashNode **buckets;  // Array of pointers to linked lists (HashNode)\n  pthread_rwlock_t rwlock;\n} HashMap;\n\nHashMap *hashmap_create(size_t size);\nvoid hashmap_put(HashMap *map, char *key, void *value);\nvoid *hashmap_get(HashMap *map, char *key);\nvoid hashmap_delete(HashMap *map, char *key, FreeDataFunc freedatafunc);\nvoid hashmap_print(HashMap *map, DataToString tostring);\nvoid hashmap_destroy(HashMap *map, FreeDataFunc freedatafunc);\n\n```\nHashMap stores key-value pairs. The hash function maps the key to an index. In case of collision, the values are moved to a seperate chain (linkedlist). The primary use here is to search a value using a key in O(1) time in the best case. \n\nWe will use the HashMap to store the Maze values and their respective Graph Node Ids. It will also be used to store pair waise distance, to speed up the miminum distance calucation.\n\n---\n\n#### LinkedList - `src/dslib/list.h`\n\n```c\ntypedef bool (*ListMatcher)(void *item, void *match);\n\ntypedef struct ListNode {\n  void *data;\n  struct ListNode *next;\n} ListNode;\n\ntypedef struct {\n  ListNode *tail;  // keeps the insertion order\n  ListNode *head;\n  size_t size;\n  pthread_rwlock_t rwlock;\n} List;\n\nList *list_create(void);\nsize_t list_add(List *list, void *data);\nsize_t list_add_at(List *list, void *data, size_t index);\nvoid *list_delete_at(List *list, size_t index, FreeDataFunc freedatafunc);\nvoid *list_get_at(List *list, size_t index);\nlong list_index_of(List *list, void *match, ListMatcher matcher);\nvoid list_print(List *list, DataToString tostring);\nvoid list_destroy(List *list, FreeDataFunc freedatafunc);\n\n```\n\nLinkedList stores the data in a sequence. It allows to access or remove the data at a particular position. We will use the list to store the isolated nodes while building the graph. Also, we will use it to store the checkpoints while distance calculation.\n\n---\n\n#### Tree - `src/dslib/tree.h`\n\n```c\ntypedef struct TreeNode {\n  size_t id;\n  void *data;\n  size_t csize;\n  struct TreeNode **children;\n  struct TreeNode *parent;\n} TreeNode;\n\ntypedef struct {\n  bool debug;\n  size_t counter;\n  DataToString tostring;\n} TreeCallbackArg;\n\ntypedef void (*TreeCallback)(TreeNode *, TreeCallbackArg *arg);\n\ntypedef struct {\n  bool debug;\n  size_t size;\n  TreeNode *root;\n  pthread_rwlock_t rwlock;\n} Tree;\n\nTree *tree_create(void);\nTreeNode *tree_find_dfs(Tree *tree, size_t nodeid);\nTreeNode *tree_find_bfs(Tree *tree, size_t nodeid);\nvoid *tree_get(Tree *tree, size_t nodeid);\nsize_t tree_insert_root(Tree *tree, void *data);\nTreeNode *tree_insert_node(Tree *tree, void *data, TreeNode *parent);\nsize_t tree_insert(Tree *tree, void *data, size_t parentid);\nsize_t tree_delete(Tree *tree, size_t nodeid, FreeDataFunc freedatafunc);\nsize_t tree_max_depth(Tree *tree);\nvoid tree_print_raw(Tree *tree, DataToString tostring);\nvoid tree_print(Tree *tree, DataToString tostring);\nvoid tree_destroy(Tree *tree, FreeDataFunc freedatafunc);\n\n```\nTree stores the data in hierarchy. Each child has a single parent and a parent can have multiple children. We will use tree to experiment with an alternate way to find the minimum distance. But it will be very memory hungry as the distance between the points on maze increases. \n\n---\n\n#### Graph - `src/dslib/graph.h`\n\n```c\n// Traversal direction will be opposite to the direction of visit\ntypedef struct {\n  size_t weight;\n  struct GraphNode *end;  // Use forward-declared GraphNode\n} GraphEdge;\n\ntypedef struct GraphNode {\n  size_t id;\n  void *data;\n  size_t esize;\n  GraphEdge **edges;\n} GraphNode;\n\ntypedef struct {\n  bool debug;\n  size_t counter;\n  DataToString tostring;\n} GraphCallbackArg;\n\ntypedef void (*GraphCallback)(GraphNode *, GraphCallbackArg *arg);\ntypedef void (*GraphDataCallback)(void *data);\ntypedef void *(*GraphDataCopier)(void *data);\n\n/**\n * Think as if a 1D array of nodes, in which a node can connect with other nodes via connections\n */\ntypedef struct {\n  bool debug;\n  size_t size;\n  List *inodes;  // isolated nodes\n  GraphNode *root;\n  pthread_rwlock_t rwlock;\n} Graph;\n\nGraph *graph_create(void);\nGraphNode *graph_find_bfs(Graph *graph, size_t nodeid);\nGraphNode *graph_find_dfs(Graph *graph, size_t nodeid);\nvoid *graph_get(Graph *graph, size_t nodeid);\n// var arg for node ids to link with other nodes\nsize_t graph_insert(Graph *graph, void *data, size_t linkcount, ...);\nsize_t graph_insert_arr(Graph *graph, void *data, size_t linkcount, size_t *nodeids);\nsize_t graph_delete(Graph *graph, size_t nodeid, FreeDataFunc freedatafunc);\nvoid graph_print(Graph *graph, DataToString tostring);\nvoid graph_traverse(Graph *graph, GraphDataCallback callback);\nGraph *graph_clone(Graph *graph, GraphDataCopier datacopier);\nvoid graph_destroy(Graph *graph, FreeDataFunc freedatafunc);\n\n```\n\nGraph is very similar to a tree, only that each children can have multiple parents. So, a node can be connected with many other nodes. The connection between nodes are called edges. We will use graph to store maze data and the path. The minimum distance between pair of points will give us the solution of the maze problem.\n\n---\n\n#### Path - `src/dslib/path.h`\n\n```c\n// this is used to send the result of the path search, id is the graph id, and data is graph data\ntypedef struct {\n  size_t id;\n  size_t cost;\n  void *data;\n} Location;\n\nLocation *location_create(void *data);\nLocation *location_clone(Location *loc);\n\nvoid free_location_data_func(void *data);\n\nchar *path_tree_data_to_string(void *arg);\n\n// non weighted graph\nStack *path_shortest_nwg_tree_vis(Graph *graph, size_t srcnodeid, size_t dstnodeid,\n                                  DataToString tostring);\n// non weighted graph\nStack *path_shortest_nwg_tree(Graph *graph, size_t srcnodeid, size_t dstnodeid);\n\n// any graph with search better algorithm\n// graph must contain location data\nStack *path_find_shortest(Graph *graph, size_t srcnodeid, size_t dstnodeid);\n\n```\n\nPath implements the algorithms to find the shortest distance using graph (based on Dijkstra algorithm) and various experimental approaches using trees.\n\n---\n\n#### BufferQueue - `src/dslib/bufferq.h`\n\n```c\ntypedef struct {\n  bool debug;\n  bool writerclosed;\n  bool readerclosed;\n  size_t capacity;\n  Queue *queue;\n  pthread_mutexattr_t mutexattr;\n  pthread_mutex_t mutex;\n  pthread_cond_t writecond;\n  pthread_cond_t readcond;\n} BufferQueue;\n\nBufferQueue *bufferq_create(size_t capacity);\nvoid bufferq_write(BufferQueue *bq, void *data);\nvoid *bufferq_read(BufferQueue *bq);\nbool bufferq_can_read(BufferQueue *bq);\nvoid bufferq_close_writer(BufferQueue *bq);\nvoid bufferq_destroy(BufferQueue *bq, FreeDataFunc freefunc);\n\n```\n\nBufferQueue data-structure allows to read and write using a fixed capacity queue. When the buffer is empty the reader will wait for more items, and when it is full then the writer will wait for items to be read. \n\nWe will use BufferQueue to process path permutation, using 1 producer thread and multiple consumer threads. This will make the maze solution finding concurrent and fast.\n\n---\n\n### Multithreading\n\nThe project has developed few structures to make multithreading simpler (src/crun). We will use `pthreads` to build our solution. \n\n\u003e A pthread, short for POSIX thread, is a unit of execution within a process in POSIX-compliant operating systems, such as Linux and Unix. The POSIX threads, or pthreads, library provides a standard API for creating and managing threads in a C or C++ program.\n\n---\n\n#### Croutine - `src/crun/croutine.h`\n\n```c\ntypedef void (*Croutine)(void *context);\n\ntypedef struct {\n  Croutine croutine;\n  void *context;\n} Execution;\n```\n\nCroutine provides a function type which will be used by a thread for executing a given task.\n\n#### Runtime - `src/crun/runtime.h`\n\n```c\ntypedef struct {\n  char *name;\n  Queue *execs;\n  pthread_mutexattr_t mutexattr;\n  pthread_mutex_t mutex;  // can acquire lock again, which rwlock does not provide\n  pthread_cond_t cond;\n  pthread_t thread;\n  bool exit;\n  bool pause;\n  bool debug;\n} Runtime;\n\nRuntime *runtime_create(void);\nvoid runtime_pause(Runtime *runtime);\nvoid runtime_resume(Runtime *runtime);\nvoid runtime_exec(Runtime *runtime, Croutine croutine, void *context);\nvoid runtime_debug(Runtime *runtime, char *name);\nvoid runtime_join_destroy(Runtime *runtime);\n\n```\n\nRuntime creates a thread and stores a queue of croutines. The thread one by one executes the croutines and then wait for more croutines.\n\n#### Runpool - `src/crun/runpool.h`\n\n```c\ntypedef struct {\n  char *name;\n  bool debug;\n  size_t size;\n  Runtime **runtimes;\n} Runpool;\n\nRunpool *runpool_create(size_t size);\nvoid runpool_exec(Runpool *pool, Croutine croutine, void *context);\nvoid runpool_debug(Runpool *pool, char *poolname);\nvoid runpool_join_destroy(Runpool *pool);\n```\n\nRunpool creates a pool of threads using Runtimes, and executes the croutines using a thread pool, in a way to maximize their execution. The free threads or thread with minimum load are given the task first.\n\n#### Pipeline - `src/crun/pipeline.h`\n\n```c\ntypedef void (*PipelineWork)(BufferQueue* bq, void* context);\n\ntypedef struct {\n  void* context;\n  PipelineWork work;\n  BufferQueue* bq;\n} PipelineContextWrap;\n\ntypedef struct {\n  bool debug;\n  BufferQueue* bq;\n  Runpool* prodpool;\n  Runpool* conspool;\n} Pipeline;\n\nPipeline* pipeline_create(size_t prodworkers, size_t consworkers,\n                          size_t capacity);\n\nvoid pipeline_add_producer(Pipeline* pipe, PipelineWork work, void* context);\nvoid pipeline_add_consumer(Pipeline* pipe, PipelineWork work, void* context);\nvoid pipeline_debug(Pipeline* pipe);\nvoid pipeline_join_destory(Pipeline* pipe,  FreeDataFunc freedatafunc);\n\n```\n\nPipeline simplifies the producer-consumer multithreded execution using BufferQueue, and Runpool.\n\n#### Pipeline example - `src/demo/puzzledemo.c`\n\n```c\n\nvoid path_permutation_producer(BufferQueue *bq, void *context) {\n  size_t arrsize = *(size_t *)context;\n  int arr[arrsize];\n\n  for (size_t i = 0; i \u003c arrsize; i++) {\n    arr[i] = i + 1;\n  }\n\n  generate_permutations_buffered(bq, arr, arrsize); // src/puzzle/utils.c\n}\n\nvoid path_permutation_consumer(BufferQueue *bq, void *context) {\n  size_t arrsize = *(size_t *)context;\n\n  while (bufferq_can_read(bq)) {\n    int *arr = (int *)bufferq_read(bq);\n    if (arr == NULL) continue;\n\n    for (size_t i = 0; i \u003c arrsize; i++) {\n      printf(\"%d \", arr[i]);\n    }\n    printf(\"\\n\");\n    sleep(2);\n  }\n}\n\nint path_permutation_pipeline_demo(void) {\n\n  // 1 producer, 3 consumers, 4 work capacity\n  Pipeline *pipe = pipeline_create(1, 3, 4);\n  pipeline_debug(pipe);\n\n  size_t *arrsize = malloc(sizeof(size_t));\n  *arrsize = 4;\n\n  // 1 producer\n  pipeline_add_producer(pipe, path_permutation_producer, arrsize);\n\n  // 3 consumers\n  pipeline_add_consumer(pipe, path_permutation_consumer, arrsize);\n  pipeline_add_consumer(pipe, path_permutation_consumer, arrsize);\n  pipeline_add_consumer(pipe, path_permutation_consumer, arrsize);\n\n  pipeline_join_destory(pipe, NULL);\n  free(arrsize);\n\n  return EXIT_SUCCESS;\n}\n```\n\n### Demo\nThe working examples of every components can be found in `src/demo`. You can execute the demo function using `src/debug/dfunc.h`\n\n```bash\nmake runclab cmd1=debug cmd2=maze_solution_demo\n```\n\n---\n\n## Detailed Discussion on the Maze Problem\n[Article - TODO]()\n\n\n## Project Structure\n```\n.\n├── Makefile\n├── README.md\n├── bin [generates on make]\n│   ├── clab [binary]\n│   └── clabdev [binary]\n├── build [generates on make]\n│   ├── dev [directory]\n│   └── release [directory]\n└── src\n    ├── crun [multithreading]\n    │   ├── clocktime.c\n    │   ├── clocktime.h\n    │   ├── croutine.h\n    │   ├── pipeline.c\n    │   ├── pipeline.h\n    │   ├── runpool.c\n    │   ├── runpool.h\n    │   ├── runtime.c\n    │   └── runtime.h\n    ├── demo [working examples]\n    │   ├── crundemo.c\n    │   ├── crundemo.h\n    │   ├── dslibdemo.c\n    │   ├── dslibdemo.h\n    │   ├── model.c\n    │   ├── model.h\n    │   ├── pathdemo.c\n    │   ├── pathdemo.h\n    │   ├── puzzledemo.c\n    │   ├── puzzledemo.h\n    │   ├── termdemo.c\n    │   └── termdemo.h\n    ├── dslib [data-structures and algorithms]\n    │   ├── bufferq.c\n    │   ├── bufferq.h\n    │   ├── datastr.c\n    │   ├── datastr.h\n    │   ├── destroy.c\n    │   ├── destroy.h\n    │   ├── dump.c\n    │   ├── graph.c\n    │   ├── graph.h\n    │   ├── hashmap.c\n    │   ├── hashmap.h\n    │   ├── list.c\n    │   ├── list.h\n    │   ├── path.c\n    │   ├── path.h\n    │   ├── queue.c\n    │   ├── queue.h\n    │   ├── stack.c\n    │   ├── stack.h\n    │   ├── tree.c\n    │   ├── tree.h\n    │   ├── util.c\n    │   └── util.h\n    ├── puzzle [maze problem]\n    │   ├── maps.txt\n    │   ├── maze.c\n    │   ├── maze.h\n    │   ├── mazesoln.c\n    │   ├── util.c\n    │   └── util.h\n    ├── term [terminal animation]\n    │   ├── console.c\n    │   └── console.h\n    ├── debug [execute single function]\n    │   ├── dfunc.c\n    │   └── dfunc.h\n    └── main.c\n    \n```\n\n## Using Project\nThe project has been tested on MacOS and Linux (Ubuntu and Kali Linux).\n\n### Build Binaries\n```bash\n# To build both dev and release binaries\nmake\n\n# To build only the dev binary\nmake dev\n\n# To build only the release binary\nmake release\n\n```\n\n### Run Dev Program\n```bash\nmake runclabdev cmd1=stack\n\n# or \nmake runclabdev cmd1=debug cmd2=maze_solution_demo\n\n# or\n./bin/clabdev stack\n\n# or\n./bin/clabdev debug maze_solution_demo\n```\n\n### Run Release Program\n```bash\nmake runclab cmd1=stack\n\n# or \nmake runclab cmd1=debug cmd2=maze_solution_demo\n\n# or\n./bin/clab stack\n\n# or\n./bin/clab debug maze_solution_demo\n```\n\n### To remove all build files and binaries\n```bash\nmake clean\n```\n\n## Run the Maze solution\n```\nmake runclab cmd1=debug cmd2=maze_solution\n\nEnter number of rows: 6\nEnter number of columns: 28\nEnter elements of the 6x28 array:\n############################\n#@...S...###........@..#####\n##...##...@...###..........#\n####.#####...........@.#####\n#.@.........@...####.....G##\n############################\n```\n\nYou will get the output solution.\n```\n...\nMaze: shortest travel distance 45\nTime taken: 0.029095 sec\n```\n\n\u003eYou can find many maze example in `src/puzzle.maps.txt`. You can copy and paste the maze in the terminal, when array is asked by the program.\n\n\u003eNote: There can be more than one solution path, but the program will show only one out of them.\n\n## Find this project useful ? :heart:\n* Support it by clicking the :star: button on the upper right of this page. :v:\n\n## More on YouTube channel - Unusual Code\nSubscribe to the YouTube channel `UnusualCode` for understanding the concepts used in this project:\n\n[![YouTube](https://img.shields.io/badge/YouTube-Subscribe-red?style=for-the-badge\u0026logo=youtube\u0026logoColor=white)](https://www.youtube.com/@unusualcode)\n\n## Contribution\nPlease feel free to fork it and open a PR (many optimization are possible). You can also add more puzzles in the project.","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funusualcodeorg%2Fclab","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Funusualcodeorg%2Fclab","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funusualcodeorg%2Fclab/lists"}