From 621400cb23e54281cc642f518aabff142dbba90f Mon Sep 17 00:00:00 2001
From: Manuel Bucher <manuel.bucher@hu-berlin.de>
Date: Wed, 13 Jun 2018 16:24:06 +0200
Subject: [PATCH] Refractored Array und List

---
 Makefile  |   2 +-
 loesung.c | 285 ++++++++++++++++++++++++++++--------------------------
 2 files changed, 147 insertions(+), 140 deletions(-)

diff --git a/Makefile b/Makefile
index 994f140..742516b 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@ all: loesung
 WARNINGS = -Wall #-Werror
 OPTIONAL = -Wextra -Wpedantic -Wshadow
 DEBUG = -g -ggdb -fno-omit-frame-pointer
-OPTIMIZE = -O2 -std=c11
+OPTIMIZE = -Og -std=c11
 
 loesung: Makefile loesung.c
 	$(CC) -o $@ $(WARNINGS) $(OPTIONAL) $(DEBUG) $(OPTIMIZE) loesung.c
diff --git a/loesung.c b/loesung.c
index 22e52f5..6ec22b1 100644
--- a/loesung.c
+++ b/loesung.c
@@ -7,13 +7,30 @@
 typedef struct Tile {
     uint32_t x;
     uint32_t y;
-    struct Tile *p_n; // north, used for initial list
+    struct Tile *p_next; // used for list
+    struct Tile *p_n; // north
     struct Tile *p_e; // east
     struct Tile *p_s; // south
     struct Tile *p_w; // west
 } Tile;
 
 
+// Reservieren und initialisieren des Speicherplatz eines Tiles
+Tile* tile_new() {
+    Tile *p_tile = malloc(sizeof(Tile));
+    if(p_tile == NULL) { // failed to allocate memory
+        return NULL;
+    }
+    p_tile->x = 0;
+    p_tile->y = 0;
+    p_tile->p_next = NULL;
+    p_tile->p_n = NULL;
+    p_tile->p_e = NULL;
+    p_tile->p_s = NULL;
+    p_tile->p_w = NULL;
+    return p_tile;
+}
+
 int tile_compare(const void *p, const void *q) {
     const Tile *s = *(const Tile**) p;
     const Tile *t = *(const Tile**) q;
@@ -35,62 +52,73 @@ int tile_compare(const void *p, const void *q) {
 /** List von Tiles */
 typedef struct List {
     Tile *p_top;
-    uint32_t size;
+    uint32_t num_tiles;
+    uint32_t num_odd; // #ungerade Felder (`x - y` ist ungerade)
+    Tile max;
+    Tile min;
 } List;
 
 /** Initialisieren einer leeren Liste */
-void list_init(List *s) {
-    s->p_top = NULL;
-    s->size = 0;
+void list_init(List *this) {
+    this->p_top = NULL;
+    this->num_tiles = 0;
+    this->num_odd = 0;
+    this->min.x = UINT32_MAX;
+    this->min.y = UINT32_MAX;
+    this->max.x = 0;
+    this->max.y = 0;
 }
 
-/** Hinzufuegen eines leeren Elementes zur Liste
+/** Min-Max funktionen fuer uint32_t */
+inline uint32_t min(uint32_t a, uint32_t b) { return a < b ? a : b; }
+inline uint32_t max(uint32_t a, uint32_t b) { return a > b ? a : b; }
+
+/** Hinzufuegen von einem Tile zur Liste
  *
  * Voraussetzung: Die Liste muss initialisiert sein.
  * Rueckgabe: Hinzugefuegtes, initialisiertes Tile
  */
-Tile* list_push(List *s) {
-    Tile *p_tile = malloc(sizeof(Tile));
-    if(p_tile == NULL) { // failed to allocate memory
-        return NULL;
-    }
-    p_tile->x = 0;
-    p_tile->y = 0;
-    p_tile->p_n = s->p_top;
-    p_tile->p_e = NULL;
-    p_tile->p_s = NULL;
-    p_tile->p_w = NULL;
-
-    s->p_top = p_tile;
-    s->size++;
-    return p_tile;
-}
-
-/** Entfernen des obersten Elementes von der Liste und zurueckgeben des Tiles
- *
- * Der List muss mindestens ein Element besitzen
- */
-Tile* list_pop(List *s) {
-    Tile *p_tile = s->p_top;
-    s->p_top = s->p_top->p_n;
-    s->size--;
-    return p_tile;
+void list_push(List *this, Tile *p_tile) {
+    p_tile->p_next = this->p_top;
+    this->p_top = p_tile;
+    // Reichweite der Liste ermitteln
+    this->min.x = min(this->min.x, p_tile->x);
+    this->min.y = min(this->min.y, p_tile->y);
+    this->max.x = max(this->max.x, p_tile->x);
+    this->max.y = max(this->max.x, p_tile->y);
+    this->num_tiles++;
+    this->num_odd += (p_tile->x - p_tile->y)&1;
 }
 
 /** Freigeben des reservierten Speichers von der Liste
  *
- * Alle Tiles weReaden mit free vom speicher deallocaiert
+ * Alle Tiles mit free vom Speicher freigeben
  */
-void list_free(List *s) {
-    Tile *p_cur = s->p_top;
-    s->p_top = NULL;
+void list_free(List *this) {
+    Tile *p_cur = this->p_top;
+    this->p_top = NULL;
     while (p_cur != NULL) {
-        Tile *p_next = p_cur->p_n;
+        Tile *p_next = p_cur->p_next;
         free(p_cur);
         p_cur = p_next;
     }
 }
 
+/** pruefen, ob genausoviele gerade und ungerade Kacheln existieren,
+ * ohne einen Overflow zu erzeugen
+ * notwendiges Kriterium fuer unzusammenhaengender graph und hinreichendes
+ * fuer zusammenhaengender
+ */
+bool list_possible(List *this) {
+    return this->num_tiles - this->num_odd == this->num_odd;
+}
+
+/** Zurueckgeben, ob graph ein vollstaendiges Rechteck ist */
+bool list_rectangle(List *this) {
+    return (this->max.x - this->min.x) * (this->max.y - this->min.y)
+        == this->num_tiles; // TODO: check for overflow?
+}
+
 typedef enum ReadResult {
     ReadOk,
     ReadEof,
@@ -100,16 +128,6 @@ typedef enum ReadResult {
     ReadErrTooManyNumbers,
     ReadErrOutOfMemory,
 } ReadResult;
-
-typedef struct Field {
-    Tile t_min;
-    Tile t_max;
-    List tile_list;
-    Tile* (*tile_array);
-    uint32_t num_tiles;
-} Field; // TODO: entfernen dieses Structs und nutzen von kleineren Strukturen:
-         //       list + tile_array
-
 /** Parsen einer Kachel(Tile) aus einer Zeile von StdIn
  *
  * Die Zahlen weReaden in das uebergebene Struct pTile geschrieben, sind aber
@@ -135,16 +153,14 @@ ReadResult read_line(Tile* p_tile){
                 cur_whitespace = false;
                 cur_number++;
             }
-            // 429496730 = 2^32 / 10, daher wenn `p_cur` groesser ist, wiRead ein
+            // 429496730 = 2^32 / 10, daher wenn `p_cur` groesser ist, wird ein
             // overflow erzeugt
             if (*p_cur > 429496729) {
-                printf("Multiplizieren ueberlauf %u\n", *p_cur);
                 return ReadErrIntegerOverflow;
             }
             (*p_cur) *= 10;
             int digit = c - '0';
             if (*p_cur > UINT32_MAX - digit) {
-                printf("Addieren ueberlauf %u\n", *p_cur);
                 return ReadErrIntegerOverflow;
             }
             (*p_cur) += digit;
@@ -166,48 +182,15 @@ ReadResult read_line(Tile* p_tile){
     return ReadOk;
 }
 
-/** Min-Max funktionen fuer uint32_t */
-inline uint32_t min(uint32_t a, uint32_t b) { return a < b ? a : b; }
-inline uint32_t max(uint32_t a, uint32_t b) { return a > b ? a : b; }
-
-/** Initialisieren der Variablen im Feld
- *
- * Voraussetzung: Speicher vom Feld muss allocated sein.
- */
-void field_init(Field *f) {
-    f->t_min.x = UINT32_MAX;
-    f->t_min.y = UINT32_MAX;
-    f->t_max.x = 0;
-    f->t_max.y = 0;
-    // initialisieren der Liste
-    list_init(&f->tile_list);
-    f->tile_array = 0;
-    f->num_tiles = 0;
-}
-
-/** Freigeben des im Heap reservierten speichers des fields f */
-void field_drop(Field *f) {
-    uint32_t num_tiles = f->tile_list.size;
-    if(f->tile_array != NULL) {
-        for(uint32_t i = 0; i < num_tiles; i++) {
-            free(f->tile_array[i]);
-        }
-        free(f->tile_array);
-    } else {
-        list_free(&f->tile_list);
-    }
-}
-
-/** Liest das Input von StdIn und schreibt das Ergebnis in das uebergebene Feld
+/** Liest das Input von StdIn und schreibt das Ergebnis in die uebergebene Liste
  *
  * Laufzeit: O(n)
  * Speicherbedarf: O(n)
  *
  * Parameter:
- *  - Field* f pointer auf ein uninitialisiertes Feld, nach dem ausfuehren der
- *    Funktion ist das Feld initialisiert, wenn es sich um eine gueltige Eingabe
- *    handelt. `f->tile_list->size` Ist im Fehlerfall die Zeile, in dem die Eingabe
- *    ungueltig ist.
+ *  - List* f ist ein Pointer auf eine initialisierte List, wird mit Eingabe
+ *    gefuellt, im Fehlerfall ist die groesse `num_tiles` die Zeile, in welche
+ *    der Fehler aufgetreten ist
  *
  * Return:
  *  - ReadResult:
@@ -215,24 +198,21 @@ void field_drop(Field *f) {
  *     ReadErr..., falls die Eingabe ungueltig ist. `f` ist dann nicht vollstaendig
  *               initialisiert
  */
-ReadResult field_init_tile_list(Field *f) {
+ReadResult parse_input(List *this) {
     while (1) {
-        Tile *t = list_push(&f->tile_list); // neues Element in die Liste einfuegen
-        if (t == NULL) {
+        Tile *p_tile = tile_new(); // neues Element erstellen
+        if (p_tile == NULL) {
             return ReadErrOutOfMemory;
         }
-        ReadResult result = read_line(t);
+        ReadResult result = read_line(p_tile);
         switch (result) {
         case ReadOk:
-            // Reichweite des Feldes ermitteln
-            f->t_min.x = min(f->t_min.x, t->x);
-            f->t_min.y = min(f->t_min.y, t->y);
-            f->t_max.x = max(f->t_max.x, t->x);
-            f->t_max.y = max(f->t_max.x, t->y);
+            // einfuegen in die Liste
+            list_push(this, p_tile);
             break;
         case ReadEof:
-            list_pop(&f->tile_list);
-            if (f->tile_list.size == 1) {
+            free(p_tile);
+            if (this->num_tiles == 0) {
                 return ReadEof;
             } else {
                 return ReadOk;
@@ -243,6 +223,24 @@ ReadResult field_init_tile_list(Field *f) {
     }
 }
 
+/** Array in heap for accessing tiles in O(1)
+ */
+typedef struct Array {
+    uint32_t num_tiles;
+    Tile* (*tiles);
+} Array;
+
+/** Freigeben des im Heap reservierten Speichers des tile_arrays f
+ * inklusive der Tiles */
+void array_drop(Array *this) {
+    if(this->tiles != NULL) {
+        for(uint32_t i = 0; i < this->num_tiles; i++) {
+            free(this->tiles[i]);
+        }
+        free(this->tiles);
+    }
+}
+
 typedef enum MallocResult {
     MallocFailed,
     MallocOk,
@@ -251,18 +249,17 @@ typedef enum MallocResult {
  *
  * Laufzeit: O(n)
  */
-MallocResult field_init_tile_array(Field *f) {
-    f->tile_array = malloc(f->tile_list.size * sizeof(Tile*));
-    if(f->tile_array == NULL) {
+MallocResult array_from_list(Array *this, List* p_list) {
+    this->tiles = malloc(p_list->num_tiles * sizeof(Tile*));
+    if(this->tiles == NULL) {
         return MallocFailed;
     }
-    Tile *cur = f->tile_list.p_top;
-    f->num_tiles = f->tile_list.size;
-
-    for (uint32_t i = 0; i < f->tile_list.size; i++) {
-        f->tile_array[i] = cur;
-        cur = cur->p_n;
-        f->tile_array[i]->p_n = NULL;
+    this->num_tiles = p_list->num_tiles;
+    Tile *cur = p_list->p_top;
+    for (uint32_t i = 0; i < this->num_tiles; i++) {
+        this->tiles[i] = cur;
+        cur = cur->p_next;
+        this->tiles[i]->p_next = NULL;
     }
     return MallocOk;
 }
@@ -273,12 +270,12 @@ MallocResult field_init_tile_array(Field *f) {
  * Rueckgabe: 0 falls alles ok
  *            1 falls Dopplungen vorkommen TODO: enum
  */
-int field_find_neighbours(Field *f) {
+int array_find_neighbours(Array *this) {
     uint32_t i = 0; // vergleich mit oberer Zeile
     uint32_t begin_line = 0;
-    for (uint32_t j = 1; j < f->num_tiles; j++) {
-        Tile *p_cur = f->tile_array[j];
-        Tile *p_east = f->tile_array[j-1];
+    for (uint32_t j = 1; j < this->num_tiles; j++) {
+        Tile *p_cur = this->tiles[j];
+        Tile *p_east = this->tiles[j-1];
         // ermitteln der ost/west-Beziehung
         if (p_cur->y == p_east->y) {
             if (p_cur->x == p_east->x) {
@@ -292,14 +289,14 @@ int field_find_neighbours(Field *f) {
             begin_line = i;
         }
         // ermitteln der nord/sued-Beziehung
-        Tile *p_north = f->tile_array[i];
+        Tile *p_north = this->tiles[i];
         if (p_north->y < p_cur->y - 1) {
             i = begin_line; // Luecke zwischen zeilen
         } else if (p_north->y == p_cur->y - 1) {
             // finden, ob paar existiert, zurzeit O(n).
             // TODO: lohnt sich binaere suche mit O(log n)?
-            for(;f->tile_array[i]->y < p_cur->y && i < begin_line; i++);
-            p_north = f->tile_array[i];
+            for(;this->tiles[i]->y < p_cur->y && i < begin_line; i++);
+            p_north = this->tiles[i];
             if (p_north->x == p_cur->x) {
                 p_north->p_s = p_cur;
                 p_cur->p_n = p_north;
@@ -309,19 +306,19 @@ int field_find_neighbours(Field *f) {
     return 0;
 }
 
-void field_print(Field *f) {
+void array_print(Array *this) {
     printf("# Array\n");
-    for (uint32_t i = 0; i < f->tile_list.size; i++) {
-        printf("%d %d\n", f->tile_array[i]->x, f->tile_array[i]->y);
+    for (uint32_t i = 0; i < this->num_tiles; i++) {
+        printf("%u %u\n", this->tiles[i]->x, this->tiles[i]->y);
     }
 }
 
 int main (void)
 {
-    // erstellen des main Objekt
-    Field field;
-    field_init(&field); // initialiseren der Variablen
-    ReadResult result = field_init_tile_list(&field); // lesen des Inputs
+    // erstellen des Liste zum parsen des inputs
+    List tile_list;
+    list_init(&tile_list); // Liste ist owner von Tiles
+    ReadResult result = parse_input(&tile_list); // lesen des Inputs
     switch (result) {
     case ReadOk:
         break;
@@ -329,44 +326,54 @@ int main (void)
         // bei leerer Eingabe nichts ausgeben
         return EXIT_SUCCESS;
     case ReadErrIntegerOverflow:
-        fprintf(stderr, "Error in line %d: too big integer\n", field.tile_list.size);
-        field_drop(&field);
+        fprintf(stderr, "Error in line %d: too big integer\n", tile_list.num_tiles);
+        list_free(&tile_list);
         return EXIT_FAILURE;
     case ReadErrNonDigitCharacter:
-        fprintf(stderr, "Error in line %d: invalid character\n", field.tile_list.size);
-        field_drop(&field);
+        fprintf(stderr, "Error in line %d: invalid character\n", tile_list.num_tiles);
+        list_free(&tile_list);
         return EXIT_FAILURE;
     case ReadErrTooFewNumbers:
         fprintf(stderr, "Error in line %d: Too few numbers, expected exactly 2\n",
-               field.tile_list.size);
-        field_drop(&field);
+                tile_list.num_tiles);
+        list_free(&tile_list);
         return EXIT_FAILURE;
     case ReadErrTooManyNumbers:
         fprintf(stderr, "Error in line %d: Too much numbers, expected exactly 2\n",
-               field.tile_list.size);
-        field_drop(&field);
+                tile_list.num_tiles);
+        list_free(&tile_list);
         return EXIT_FAILURE;
     case ReadErrOutOfMemory:
         fprintf(stderr, "Error in line %d: Failed to allocate more memory",
-                field.tile_list.size);
+                tile_list.num_tiles);
+        list_free(&tile_list);
         return EXIT_FAILURE;
     }
-    // turn the list into an array
-    if(field_init_tile_array(&field) == MallocFailed) {
+    Array tile_array;
+    // uebertragen der Liste in ein Array, und uebergeben des ownership der Tiles
+    // an das Array
+    if(array_from_list(&tile_array, &tile_list) == MallocFailed) {
         fprintf(stderr, "Error: Failed to allocate enough memory");
+        list_free(&tile_list); // fehlgeschlagen, noch ist liste owner.
+        return EXIT_FAILURE;
     }
-    qsort(field.tile_array, field.tile_list.size, sizeof(Tile*), tile_compare);
 
-    if(field_find_neighbours(&field)) {
+    // TODO: pruefen, ob notwendiges Kriterium erfuellt,
+    // TODO: Falls Rechteck, dieses Ausgeben.
+
+    //array_print(&tile_array);
+    qsort(tile_array.tiles, tile_array.num_tiles, sizeof(Tile*), tile_compare);
+
+    if(array_find_neighbours(&tile_array)) {
         fprintf(stderr, "Error: Duplicated entry\n");
+        array_drop(&tile_array);
         return EXIT_FAILURE;
     }
-    //field_print(&field);
 
     // TODO: Untertilesets finden
-    // TODO: Problem fuer die Untertilesets loesen
-    // TODO: Loesung ausgeben
+    // TODO: Pro Untertileset schauen ob notwendiges kriterium
+    // TODO: Loesung ausgeben (schwerer Teil)
 
-    field_drop(&field);
+    array_drop(&tile_array);
     return EXIT_SUCCESS;
 }
-- 
GitLab