diff --git a/src/HPModel.cpp b/src/HPModel.cpp
index ac100b11220f835fd8b30b6e8fb7c03164efd3ca..a5191f736ce18030dbe87289bdb2f266dffab1dd 100644
--- a/src/HPModel.cpp
+++ b/src/HPModel.cpp
@@ -11,10 +11,10 @@ Point::Point(const int x, const int y, const int z, const bool hydrophobic)
 
 void Point::print() const {
     std::cout << "Point (" << x << ", " << y << ", " << z << ")\n";
-    std::cout << (hydrophobic ? " - Hydrophobic (H)" : " - Polar (P)") << "\n";
+    //std::cout << (hydrophobic ? " - Hydrophobic (H)" : " - Polar (P)") << "\n";
 }
 
-bool Point::coords_match(Point other) {
+bool Point::coords_match(Point other) const {
     return other.x == x && other.y == y && other.z == z;
 }
 
@@ -23,6 +23,7 @@ bool Point::coords_match(Point other) {
 HPModel::HPModel(const std::string &input_sequence) {
     currentDirection = NORTH;
     previousDirection = NORTH;
+    rotation = NO_ROTATION;
     if (input_sequence.size() < 2) {
         throw std::invalid_argument("Sequence length must be at least 2");
     }
@@ -68,6 +69,37 @@ bool HPModel::isInsertValid(Point toInsert) {
     return true;
 }
 
+/**
+ * Updates the rotation in 90 degree steps
+ * POSITIVE = CLOCKWISE
+ * NEGATIVE = COUNTER CLOCKWISE
+ * @param amount amount of steps to rotate, for each step rotates 90 degrees, negative amount will rotate opposite direction
+ */
+void HPModel::rotate(int amount) {
+    // Since a rotation step is 90 degrees, every 4 rotations will be 360 degrees
+    int modAmount = amount % 4;
+    int rotationTimes = modAmount;
+    if (modAmount < 0) {
+        rotationTimes = 4 - (-modAmount);
+    }
+    for (int i = 0; i < rotationTimes; i++) {
+        switch (rotation) {
+            case NO_ROTATION:
+                rotation = ROTATE_90;
+                break;
+            case ROTATE_90:
+                rotation = ROTATE_180;
+                break;
+            case ROTATE_180:
+                rotation = ROTATE_270;
+                break;
+            case ROTATE_270:
+                rotation = NO_ROTATION;
+                break;
+        }
+    }
+}
+
 ABSOLUTE_DIRECTION
 HPModel::getPlaneDirectionChange(ABSOLUTE_DIRECTION absolute_direction, DIRECTION relative_direction) {
     if (absolute_direction == ABS_UP || absolute_direction == ABS_DOWN || relative_direction == UP ||
@@ -108,16 +140,84 @@ HPModel::getPlaneDirectionChange(ABSOLUTE_DIRECTION absolute_direction, DIRECTIO
     }
 }
 
-void HPModel::updateCurrentDirection(DIRECTION direction) {
+/*
+ * Has the side effect of updating previousDirection, because this update is non-trivial
+ * Similarly updates the rotation, because up/down are the only folds that will do so
+ */
+ABSOLUTE_DIRECTION HPModel::getUpDownDirectionAndUpdatePrevious(DIRECTION relative_direction) {
+    if (relative_direction != UP && relative_direction != DOWN) {
+        throw std::invalid_argument("Invalid direction passed, must be either UP/DOWN\n");
+    }
     ABSOLUTE_DIRECTION new_direction;
-    switch (direction) {
-        case FORWARD:
-            if (currentDirection != ABS_UP && currentDirection != ABS_DOWN) {
-                new_direction = currentDirection;
+    switch (currentDirection) {
+        case NORTH:
+        case EAST:
+        case SOUTH:
+        case WEST:
+            if (relative_direction == UP) {
+                // NORTH/EAST/SOUTH/WEST -> UP
+                new_direction = ABS_UP;
             } else {
-                new_direction = previousDirection;
+                // NORTH/EAST/SOUTH/WEST -> DOWN
+                new_direction = ABS_DOWN;
+            }
+            // Note: in this case we DO NOT want to update the previous direction
+            break;
+        case ABS_UP:
+            switch (previousDirection) {
+                case NORTH:
+                case EAST:
+                case SOUTH:
+                case WEST:
+                    if (relative_direction == UP) {
+                        // UP -> UP
+                        new_direction = invertDirection(previousDirection);
+                        // After UP -> UP we will be "upside-down" and will need to rotate 180 degrees
+                        rotate(2);
+                    } else {
+                        // UP -> DOWN
+                        new_direction = previousDirection;
+                        // No rotation required because this is equivalent to simply FORWARD
+                    }
+                    break;
+                case ABS_UP:
+                case ABS_DOWN:
+                    throw std::invalid_argument("Both current and previous direction is UP/DOWN, illegal state\n");
             }
             break;
+        case ABS_DOWN:
+            switch (previousDirection) {
+                case NORTH:
+                case EAST:
+                case SOUTH:
+                case WEST:
+                    if (relative_direction == UP) {
+                        // DOWN -> UP
+                        new_direction = previousDirection;
+                        // No rotation required
+                    } else {
+                        // DOWN -> DOWN
+                        new_direction = invertDirection(previousDirection);
+                        // DOWN -> DOWN results in "upside-down" state just as UP -> UP does
+                        rotate(-2);
+                    }
+                    break;
+                case ABS_UP:
+                case ABS_DOWN:
+                    throw std::invalid_argument("Both current and previous direction is UP/DOWN, illegal state\n");
+            }
+            break;
+    }
+    return new_direction;
+}
+
+void HPModel::updateCurrentDirection(DIRECTION direction) {
+    ABSOLUTE_DIRECTION new_direction;
+    DIRECTION rotated_direction = getRotatedRelativeDirection(direction);
+    switch (rotated_direction) {
+        case FORWARD:
+            new_direction = currentDirection;
+            break;
         case RIGHT:
         case LEFT:
             switch (currentDirection) {
@@ -125,26 +225,58 @@ void HPModel::updateCurrentDirection(DIRECTION direction) {
                 case SOUTH:
                 case EAST:
                 case WEST:
-                    new_direction = getPlaneDirectionChange(currentDirection, direction);
+                    new_direction = getPlaneDirectionChange(currentDirection, rotated_direction);
                     break;
                 case ABS_UP:
                 case ABS_DOWN:
-                    new_direction = getPlaneDirectionChange(previousDirection, direction);
+                    // In this case we need to handle rotation changes, because moving "out" of an UP/DOWN forces a rotation
+                    if (currentDirection == ABS_UP) {
+                        // UP
+                        if (rotated_direction == RIGHT) {
+                            // UP -> RIGHT
+                            rotate(1);
+                        } else {
+                            // UP -> LEFT
+                            rotate(-1);
+                        }
+                    } else {
+                        // DOWN
+                        if (rotated_direction == RIGHT) {
+                            // DOWN -> RIGHT
+                            rotate(-1);
+                        } else {
+                            // DOWN -> LEFT
+                            rotate(1);
+                        }
+                    }
+                    new_direction = getPlaneDirectionChange(previousDirection, rotated_direction);
                     break;
                 default:
-                    throw std::invalid_argument("Enum value: " + directionToString(direction) + " is invalid\n");
+                    throw std::invalid_argument("Enum value: " + directionToString(rotated_direction) + " is invalid\n");
             }
             break;
         case UP:
-            new_direction = ABS_UP;
+            //new_direction = ABS_UP;
+            new_direction = getUpDownDirectionAndUpdatePrevious(rotated_direction);
             break;
         case DOWN:
-            new_direction = ABS_DOWN;
+            //new_direction = ABS_DOWN;
+            new_direction = getUpDownDirectionAndUpdatePrevious(rotated_direction);
             break;
         default:
-            throw std::invalid_argument("Enum value: " + directionToString(direction) + " is invalid\n");
+            throw std::invalid_argument("Enum value: " + directionToString(rotated_direction) + " is invalid\n");
     }
 
+    // ABS_UP/ABS_DOWN are handled directly in getUpDownDirectionAndUpdatePrevious
+    if ((new_direction == ABS_UP || new_direction == ABS_DOWN) && (currentDirection == ABS_UP || currentDirection == ABS_DOWN)) {
+        currentDirection = new_direction;
+        return;
+    }
+    if ((new_direction == ABS_UP || new_direction == ABS_DOWN) && (previousDirection == ABS_UP || previousDirection == ABS_DOWN)) {
+        previousDirection = currentDirection;
+        currentDirection = new_direction;
+        return;
+    }
     if (new_direction != previousDirection) {
         previousDirection = currentDirection;
     }
@@ -169,7 +301,8 @@ void HPModel::fold(DIRECTION direction) {
     // At this point, there exists k folds, and no_of_points = k + 1 => k = no_of_points - 1
     // We want k <= n - 1, thus we need, no_of_points - 1 < n - 1 => no_of_points < n
     if (no_of_points >= sequence.size()) {
-        throw std::invalid_argument("Too many folds when trying to insert fold number " + std::to_string(no_of_points - 1));
+        throw std::invalid_argument(
+                "Too many folds when trying to insert fold number " + std::to_string(no_of_points - 1));
     }
     addPoint(direction, isCurrentAcidHydrophobic());
 }
@@ -222,3 +355,65 @@ void HPModel::print() const {
 std::vector<Point> HPModel::getPoints() {
     return acids;
 }
+
+ABSOLUTE_DIRECTION HPModel::invertDirection(ABSOLUTE_DIRECTION direction) {
+    switch (direction) {
+
+        case NORTH:
+            return SOUTH;
+        case EAST:
+            return WEST;
+        case SOUTH:
+            return NORTH;
+        case WEST:
+            return EAST;
+        case ABS_UP:
+        case ABS_DOWN:
+            throw std::invalid_argument("Unable to invert direction of ABS_UP/ABS_DOWN directions\n");
+            break;
+    }
+}
+
+DIRECTION rotateRelativeDirection90Degrees(DIRECTION relativeDirection) {
+    switch (relativeDirection) {
+        case FORWARD:
+            return FORWARD;
+        case UP:
+            return RIGHT;
+        case DOWN:
+            return LEFT;
+        case LEFT:
+            return UP;
+        case RIGHT:
+            return DOWN;
+    }
+}
+
+/**
+ * Rotates a relative direction based on the current rotation
+ */
+DIRECTION HPModel::getRotatedRelativeDirection(DIRECTION relative_direction) {
+    int rotateAmount;
+
+    switch (rotation) {
+        case NO_ROTATION:
+            rotateAmount = 0;
+            break;
+        case ROTATE_90:
+            rotateAmount = 1;
+            break;
+        case ROTATE_180:
+            rotateAmount = 2;
+            break;
+        case ROTATE_270:
+            rotateAmount = 3;
+            break;
+    }
+
+    DIRECTION new_relative_direction = relative_direction;
+    for (int i = 0; i < rotateAmount; i++) {
+        new_relative_direction = rotateRelativeDirection90Degrees(new_relative_direction);
+    }
+
+    return new_relative_direction;
+}
\ No newline at end of file
diff --git a/src/HPModel.h b/src/HPModel.h
index c17a736aa9eaa6ee84af2290d43ba28f6c9020c4..4409c929e39299aa20900c76d7927ba653b96a52 100644
--- a/src/HPModel.h
+++ b/src/HPModel.h
@@ -9,6 +9,7 @@
 
 enum DIRECTION {FORWARD, UP, DOWN, LEFT, RIGHT};
 enum ABSOLUTE_DIRECTION {NORTH, EAST, SOUTH, WEST, ABS_UP, ABS_DOWN};
+enum ROTATION {NO_ROTATION, ROTATE_90, ROTATE_180, ROTATE_270};
 
 class Point {
 public:
@@ -17,7 +18,7 @@ public:
     Point(const int x, const int y, const int z, const bool hydrophobic);
 
     void print() const;
-    bool coords_match(Point other);
+    bool coords_match(Point other) const;
 };
 
 class HPModel {
@@ -26,13 +27,19 @@ private:
     std::vector<Point> acids;
     ABSOLUTE_DIRECTION currentDirection;
     ABSOLUTE_DIRECTION previousDirection;
+    ROTATION rotation;
     Point getHead();
     static std::string directionToString(DIRECTION direction);
     bool isInsertValid(Point toInsert);
     bool isCurrentAcidHydrophobic();
-    ABSOLUTE_DIRECTION getPlaneDirectionChange(ABSOLUTE_DIRECTION absolute_direction, DIRECTION relative_direction);
+    static ABSOLUTE_DIRECTION getPlaneDirectionChange(ABSOLUTE_DIRECTION absolute_direction, DIRECTION relative_direction);
+    ABSOLUTE_DIRECTION getUpDownDirectionAndUpdatePrevious(DIRECTION relative_direction);
     void updateCurrentDirection(DIRECTION direction);
     void addPoint(DIRECTION direction, bool isHydrophobic);
+    void rotate(int amount);
+    DIRECTION getRotatedRelativeDirection(DIRECTION relative_direction);
+    static ABSOLUTE_DIRECTION invertDirection(ABSOLUTE_DIRECTION direction);
+
 public:
     std::vector<Point> getPoints();
     void fold(DIRECTION direction);
diff --git a/test/basic_tests/basic_check.cpp b/test/basic_tests/basic_check.cpp
index cde246646060eb5d807e1cd28d93bceff0ddac60..68302fbc7483b16a9bb88a805916cb5a1e6c9fef 100644
--- a/test/basic_tests/basic_check.cpp
+++ b/test/basic_tests/basic_check.cpp
@@ -68,6 +68,86 @@ TEST(basic_check, test_planar) {
     EXPECT_TRUE(p4.coords_match(p4Match));
 }
 
+TEST(basic_check, test_up_loop_valid) {
+    HPModel model = HPModel("pppp");
+    model.fold(UP);
+    model.fold(UP);
+    model.fold(UP);
+
+    auto points = model.getPoints();
+
+    // Initial Point
+    Point p0 = points[0];
+    Point p0Match = Point(0, 0, 0, false);
+
+    // Up
+    Point p1 = points[1];
+    Point p1Match = Point(0, 1, 0, false);
+
+    // Up
+    Point p2 = points[2];
+    Point p2Match = Point(0, 1, -1, false);
+
+    // Up
+    Point p3 = points[3];
+    Point p3Match = Point(0, 0, -1, false);
+
+    model.print();
+
+    EXPECT_TRUE(p0.coords_match(p0Match));
+    EXPECT_TRUE(p1.coords_match(p1Match));
+    EXPECT_TRUE(p2.coords_match(p2Match));
+    EXPECT_TRUE(p3.coords_match(p3Match));
+}
+
+TEST(basic_check, test_up_relative_valid) {
+    HPModel model = HPModel("ppppp");
+    model.fold(UP);
+    model.fold(RIGHT);
+    model.fold(LEFT);
+    model.fold(LEFT);
+
+    auto points = model.getPoints();
+
+    // Initial Point
+    Point p0 = points[0];
+    Point p0Match = Point(0, 0, 0, false);
+
+    // Up
+    Point p1 = points[1];
+    Point p1Match = Point(0, 1, 0, false);
+
+    // Right
+    Point p2 = points[2];
+    Point p2Match = Point(1, 1, 0, false);
+
+    // Left
+    Point p3 = points[3];
+    Point p3Match = Point(1, 2, 0, false);
+
+    // Left
+    Point p4 = points[4];
+    Point p4Match = Point(0, 2, 0, false);
+
+    model.print();
+
+    EXPECT_TRUE(p0.coords_match(p0Match));
+    EXPECT_TRUE(p1.coords_match(p1Match));
+    EXPECT_TRUE(p2.coords_match(p2Match));
+    EXPECT_TRUE(p3.coords_match(p3Match));
+    EXPECT_TRUE(p4.coords_match(p4Match));
+}
+
+TEST(basic_check, test_up_loop_invalid) {
+    HPModel model = HPModel("ppppp");
+    model.fold(UP);
+    model.fold(UP);
+    model.fold(UP);
+    EXPECT_THROW(model.fold(UP), std::invalid_argument);
+    model.print();
+}
+
+
 TEST(basic_check, test_up_down) {
     HPModel model = HPModel("pppppp");
     model.fold(RIGHT);
@@ -91,15 +171,69 @@ TEST(basic_check, test_up_down) {
 
     // Forward
     Point p3 = points[3];
-    Point p3Match = Point(2, 1, 0, false);
+    Point p3Match = Point(1, 2, 0, false);
 
     // Down
     Point p4 = points[4];
-    Point p4Match = Point(2, 0, 0, false);
+    Point p4Match = Point(2, 2, 0, false);
 
     // Left
     Point p5 = points[5];
-    Point p5Match = Point(2, 0, 1, false);
+    Point p5Match = Point(2, 2, 1, false);
+
+    EXPECT_TRUE(p0.coords_match(p0Match));
+    EXPECT_TRUE(p1.coords_match(p1Match));
+    EXPECT_TRUE(p2.coords_match(p2Match));
+    EXPECT_TRUE(p3.coords_match(p3Match));
+    EXPECT_TRUE(p4.coords_match(p4Match));
+    EXPECT_TRUE(p5.coords_match(p5Match));
+}
+
+TEST(basic_check, big_test) {
+    HPModel model = HPModel("pppppppp");
+    model.fold(DOWN);
+    model.fold(DOWN);
+    model.fold(RIGHT);
+    model.fold(DOWN);
+    model.fold(RIGHT);
+    model.fold(UP);
+    model.fold(LEFT);
+
+    auto points = model.getPoints();
+
+    model.print();
+
+    // Initial point
+    Point p0 = points[0];
+    Point p0Match = Point(0, 0, 0, false);
+
+    // Down
+    Point p1 = points[1];
+    Point p1Match = Point(0, -1, 0, false);
+
+    // Down
+    Point p2 = points[2];
+    Point p2Match = Point(0, -1, -1, false);
+
+    // Right
+    Point p3 = points[3];
+    Point p3Match = Point(1, -1, -1, false);
+
+    // Down
+    Point p4 = points[4];
+    Point p4Match = Point(1, 0, -1, false);
+
+    // Right
+    Point p5 = points[5];
+    Point p5Match = Point(1, 0, 0, false);
+
+    // Up
+    Point p6 = points[6];
+    Point p6Match = Point(2, 0, 0, false);
+
+    // Left
+    Point p7 = points[7];
+    Point p7Match = Point(2, 1, 0, false);
 
     EXPECT_TRUE(p0.coords_match(p0Match));
     EXPECT_TRUE(p1.coords_match(p1Match));
@@ -107,4 +241,45 @@ TEST(basic_check, test_up_down) {
     EXPECT_TRUE(p3.coords_match(p3Match));
     EXPECT_TRUE(p4.coords_match(p4Match));
     EXPECT_TRUE(p5.coords_match(p5Match));
+    EXPECT_TRUE(p6.coords_match(p6Match));
+    EXPECT_TRUE(p7.coords_match(p7Match));
+}
+
+TEST(basic_check, right_up) {
+    HPModel model = HPModel("ppppp");
+    model.fold(RIGHT);
+    model.fold(UP);
+    model.fold(UP);
+    model.fold(RIGHT);
+
+    auto points = model.getPoints();
+
+    // Initial
+    Point p0 = points[0];
+    Point p0Match = Point(0, 0, 0, false);
+
+    // Right
+    Point p1 = points[1];
+    Point p1Match = Point(1, 0, 0, false);
+
+    // Up
+    Point p2 = points[2];
+    Point p2Match = Point(1, 1, 0, false);
+
+    // Up
+    Point p3 = points[3];
+    Point p3Match = Point(0, 1, 0, false);
+
+
+    // Right
+    Point p4 = points[4];
+    Point p4Match = Point(0, 1, -1, false);
+
+    model.print();
+
+    EXPECT_TRUE(p0.coords_match(p0Match));
+    EXPECT_TRUE(p1.coords_match(p1Match));
+    EXPECT_TRUE(p2.coords_match(p2Match));
+    EXPECT_TRUE(p3.coords_match(p3Match));
+    EXPECT_TRUE(p4.coords_match(p4Match));
 }
\ No newline at end of file