diff --git a/hashtable.c b/hashtable.c
index 0d286e44ae75b609cf8f8475fab4f6be8b6d0da0..7e2c0dd9c5ef9d6a94b36e894d66dafc4419a3ea 100644
--- a/hashtable.c
+++ b/hashtable.c
@@ -8,30 +8,156 @@
 #include <stdlib.h>
 #include <string.h>
 
+int hash(char *key, int64_t length) {
+    // If the size of the int is too low the hash methods will generate overflow errors
+    int64_t val = 0;
+    for (size_t i = 0; i < strlen(key); i++) {
+        val = 43 * val + key[i];
+    }
+    return (val % length);
+}
+
+entry *entry_create_empty() {
+    entry *e = malloc(sizeof(entry));
+    e->key = NULL;
+    e->value = NULL;
+    e->next = NULL;
+    return e;
+}
+
 hm *hm_create(unsigned int length) {
-    return NULL;
+    hm *hashmap = malloc(sizeof(hm));
+    hashmap->length = length;
+    hashmap->entries = malloc(sizeof(entry) * length);
+    for (size_t i = 0; i < length; i++) {
+        hashmap->entries[i] = entry_create_empty();
+    }
+
+    return hashmap;
 }
 
-void hm_destroy(hm **hm) {
+entry *get_entry_by_key(entry *e, char *key) {
+    if (e->key == key) {
+        return e;
+    } else if (e->next != NULL) {
+        return get_entry_by_key(e->next, key);
+    } else {
+        return e;
+    }
+}
 
+void hm_destroy(hm **hm) {
+    for (int i = 0; i < (*hm)->length; i++) {
+        entry *e = (*hm)->entries[i];
+        while (e != NULL) {
+            entry *to_free = e;
+            e = e->next;
+            free(to_free);
+        }
+    }
+    free((*hm)->entries);
+    free((*hm));
+    (*hm) = NULL;
 }
 
 hm *hm_set(hm *hm, const char *const key, const char *const value) {
-    return NULL;
+    // Hash the key and get the corresponding entry
+    int key_index = hash((char *)key, hm->length);
+    entry *e = get_entry_by_key(hm->entries[key_index], (char *)key);
+
+    // Set the key and create the next entry if the key is not existing
+    if (e->key != key) {
+        e->key = (char *)key;
+        if (e->next == NULL) {
+            e->next = entry_create_empty();
+        }
+    }
+
+    // Set the entry value and return the hashmap
+    e->value = (char *)value;
+    return hm;
 }
 
 char *hm_get(const hm *const hm, const char *const key) {
-    return NULL;
+    int key_index = hash((char *)key, hm->length);
+    char *c = get_entry_by_key(hm->entries[key_index], (char *)key)->value;
+    return c;
 }
 
 char *hm_rm(hm *hm, const char *const key) {
-    return NULL;
+    int key_index = hash((char *)key, hm->length);
+    entry *e = get_entry_by_key(hm->entries[key_index], (char *)key);
+    entry *previous_entry = NULL;
+    entry *current_entry = hm->entries[key_index];
+    int entry_index = 0;
+
+    while (current_entry != e) {
+        previous_entry = current_entry;
+        current_entry = current_entry->next;
+        entry_index++;
+    }
+
+    if (entry_index == 0) {
+        hm->entries[key_index] = hm->entries[key_index]->next;
+    } else if (previous_entry != NULL) {
+        previous_entry->next = e->next;
+    }
+
+    char *entry_key = e->key;
+    free(e);
+    e = NULL;
+    return entry_key;
+}
+
+int get_entry_list_size(entry *e) {
+    int size = 0;
+    size += sizeof(e->key) + sizeof(e->value) + 16;
+    if (e->next != NULL) {
+        size += get_entry_list_size(e->next);
+    }
+    return size;
 }
 
-char *hmo_str(const hm *const hm) {
-    return NULL;
+char *hm_to_str(const hm *const hm) {
+    int str_size = sizeof(hm) * hm->length;
+    for (int i = 0; i < hm->length; i++) {
+        str_size += get_entry_list_size(hm->entries[i]);
+    }
+
+    char *hm_str = malloc(str_size);
+    // Ensure that the string is empty before doing anything
+    hm_str[0] = '\0';
+
+    strcat(hm_str, "[\n");
+    for (int i = 0; i < hm->length; i++) {
+        strcat(hm_str, "    [\n");
+        entry *e = hm->entries[i];
+        while (e != NULL && e->key != NULL) {
+            strcat(hm_str, "        [\"");
+            strcat(hm_str, e->key);
+            strcat(hm_str, "\": \"");
+            strcat(hm_str, e->value);
+            strcat(hm_str, "\"]");
+            if (e->next != NULL && e->next->key != NULL) {
+                strcat(hm_str, ",");
+            }
+            strcat(hm_str, "\n");
+            e = e->next;
+        }
+
+        strcat(hm_str, "    ]");
+        if (i < hm->length - 1) {
+            strcat(hm_str, ",");
+        }
+        strcat(hm_str, "\n");
+    }
+
+    strcat(hm_str, "]\n");
+    return hm_str;
 }
 
 void hm_print(const hm *const hm) {
-    return NULL;
+    char *str = hm_to_str(hm);
+    printf("%s\n", str);
+    free(str);
 }
diff --git a/main.c b/main.c
index df0280e64212cccf9b2028951c8713148afd51ff..354750d38c22c7b42850d723360c65dcd019062c 100644
--- a/main.c
+++ b/main.c
@@ -5,7 +5,60 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+#include "hashtable.h"
 
 int main() {
+    srand(0);
+    hm *hashmap = hm_create(5);
+
+    while (true) {
+        printf("Add (1), Delete (2), Search (3), Print (4), Exit (5)...\n");
+        int selection;
+        scanf("%d", &selection);
+        if (selection < 1 || selection > 5) {
+            printf("Bad input, try again.\n");
+            continue;
+        }
+        char phone[10];
+        char name[10];
+
+        if (selection == 1) {
+            printf("Phone :\n");
+            scanf("%s", phone);
+            printf("Name :\n");
+            scanf("%s", name);
+            char *p = strdup(phone);
+            char *n = strdup(name);
+            hm_set(hashmap, p, n);
+            hm_print(hashmap);
+            free(n);
+            free(p);
+        }
+        if (selection == 2) {
+            printf("Phone to delete :\n");
+            scanf("%s", phone);
+            hm_rm(hashmap, phone);
+            hm_print(hashmap);
+        }
+        if (selection == 3) {
+            printf("Phone to search :\n");
+            scanf("%s", phone);
+            char *p = strdup(phone);
+            char *name = hm_get(hashmap, p);
+            if (name != NULL) {
+                printf("%s\n", name);
+            }
+        }
+        if (selection == 4) {
+            hm_print(hashmap);
+        }
+        if (selection == 5) {
+            break;
+        }
+    }
+
+    hm_destroy(&hashmap);
+
     return EXIT_SUCCESS;
 }