diff --git a/src/main/java/edu/unl/cse/bohn/StringBox.java b/src/main/java/edu/unl/cse/bohn/StringBox.java
index d0d3d2849b12020425a351b744db04278c547f33..820441e62948e3c3ea892125f2bcc29531ea0c62 100644
--- a/src/main/java/edu/unl/cse/bohn/StringBox.java
+++ b/src/main/java/edu/unl/cse/bohn/StringBox.java
@@ -23,6 +23,16 @@ package edu.unl.cse.bohn;
  * <p>Note that StringBox is <i>not</i> robust to hidden characters, such as VT100 escape sequences.</p>
  */
 public class StringBox {
+    /**
+     * Horizontal alignment directives
+     */
+    public enum Horizontal {LEFT, RIGHT}
+
+    /**
+     * Vertical alignment directives
+     */
+    public enum Vertical {TOP, BOTTOM}
+
     private int maximumWidth;
     private int maximumHeight;
     private int logicalHeight;
@@ -89,9 +99,59 @@ public class StringBox {
      * @see #placeStringAlignTopLeft(String, int, int)
      */
     public StringBox placeString(String string, int topRow, int leftColumn) {
-        return placeStringAlignTopLeft(string, topRow, leftColumn);
+        return placeString(string, Vertical.TOP, topRow, Horizontal.LEFT, leftColumn);
+    }
+
+    /**
+     * <p>Places a string in the StringBox. If <code>verticalAlignment</code> is <code>TOP</code> then the string's
+     * first line will be in the <code>verticalPosition</code>'th row, and each subsequent line will be in each
+     * subsequent row. If <code>verticalAlignment</code> is <code>BOTTOM</code> then the string's last line will be in
+     * the <code>verticalPosition</code>'th row, and each preceding line will be in each preceding row. If
+     * <code>horizontalAlignment</code> is <code>LEFT</code> then each line will be left-justified to the
+     * <code>horizontalPosition</code>'th column. If <code>horizontalAlignment</code> is <code>RIGHT</code> then each
+     * line will be right-justified to the <code>horizontalPosition</code>'th column.</p>
+     *
+     * @param string              the string to be placed in the StringBox
+     * @param verticalAlignment   vertical alignment directive (top/bottom)
+     * @param verticalPosition    the row on which the string should be top/bottom aligned
+     * @param horizontalAlignment horizontal alignment directive (left/right)
+     * @param horizontalPosition  the column on which the string should be top/bottom aligned
+     * @return the current StringBox object, suitable for chained calls
+     */
+    public StringBox placeString(String string, Vertical verticalAlignment, int verticalPosition,
+                                 Horizontal horizontalAlignment, int horizontalPosition) {
+        String[] strings = string.split(System.lineSeparator());
+        // This would benefit from the switch expression in JDK 12/13
+        int topRow = verticalAlignment == Vertical.TOP ? verticalPosition :
+                    verticalAlignment == Vertical.BOTTOM ? verticalPosition - strings.length + 1 :
+                            0;
+        int firstRow = Math.max(topRow, 0);
+        int lastRow = Math.min(topRow + strings.length, maximumHeight);
+        int offset = -topRow;
+        for (int i = firstRow; i < lastRow; i++) {
+            switch (horizontalAlignment) {
+                case LEFT:
+                    rows[i].placeSubstringAlignLeft(strings[i + offset], horizontalPosition);
+                    break;
+                case RIGHT:
+                    rows[i].placeSubstringAlignRight(strings[i + offset], horizontalPosition);
+                    break;
+                default:
+                    System.err.println("Unreachable code was reached in StringBox.placeString()!");
+                    System.err.println("\thorizontalAlignment == " + horizontalAlignment);
+                    Horizontal recoveryAlignment = Horizontal.LEFT;
+                    System.err.println("\tAttempting to recover with horizontalAlignment = " + recoveryAlignment);
+                    rows[i].placeSubstringAlignLeft(strings[i + offset], horizontalPosition);
+            }
+        }
+        logicalHeight = Math.max(logicalHeight, lastRow);
+        return this;
     }
 
+    /* ******************
+     *  LEGACY METHODS  *
+     ********************/
+
     /**
      * Places a string in the StringBox with its upper-left corner in the specified location. If the string
      * contains multiple lines, each line after the first will be placed in the row subsequent to the previous line,
@@ -104,15 +164,7 @@ public class StringBox {
      * @return the current StringBox object, suitable for chained calls
      */
     public StringBox placeStringAlignTopLeft(String string, int topRow, int leftColumn) {
-        String[] strings = string.split("\n");
-        int firstRow = Math.max(topRow, 0);
-        int lastRow = Math.min(topRow + strings.length, maximumHeight);
-        int offset = -topRow;
-        for (int i = firstRow; i < lastRow; i++) {
-            rows[i].placeSubstringAlignLeft(strings[i + offset], leftColumn);
-        }
-        logicalHeight = Math.max(logicalHeight, lastRow);
-        return this;
+        return placeString(string, Vertical.TOP, topRow, Horizontal.LEFT, leftColumn);
     }
 
     /**
@@ -127,8 +179,7 @@ public class StringBox {
      * @return the current StringBox object, suitable for chained calls
      */
     public StringBox placeStringAlignBottomLeft(String string, int bottomRow, int leftColumn) {
-        String[] strings = string.split("\n");
-        return placeStringAlignTopLeft(string, bottomRow - strings.length + 1, leftColumn);
+        return placeString(string, Vertical.BOTTOM, bottomRow, Horizontal.LEFT, leftColumn);
     }
 
     /**
@@ -143,15 +194,7 @@ public class StringBox {
      * @return the current StringBox object, suitable for chained calls
      */
     public StringBox placeStringAlignTopRight(String string, int topRow, int rightColumn) {
-        String[] strings = string.split("\n");
-        int firstRow = Math.max(topRow, 0);
-        int lastRow = Math.min(topRow + strings.length, maximumHeight);
-        int offset = -topRow;
-        for (int i = firstRow; i < lastRow; i++) {
-            rows[i].placeSubstringAlignRight(strings[i + offset], rightColumn);
-        }
-        logicalHeight = Math.max(logicalHeight, lastRow);
-        return this;
+        return placeString(string, Vertical.TOP, topRow, Horizontal.RIGHT, rightColumn);
     }
 
     /**
@@ -166,10 +209,13 @@ public class StringBox {
      * @return the current StringBox object, suitable for chained calls
      */
     public StringBox placeStringAlignBottomRight(String string, int bottomRow, int rightColumn) {
-        String[] strings = string.split("\n");
-        return placeStringAlignTopRight(string, bottomRow - strings.length + 1, rightColumn);
+        return placeString(string, Vertical.BOTTOM, bottomRow, Horizontal.RIGHT, rightColumn);
     }
 
+    /* *************************
+     *  END OF LEGACY METHODS  *
+     ***************************/
+
     /**
      * <p>Generates the string that the client code produced by calling {@link #placeString(String, int, int)} and
      * its related methods. Any unused lines between the last line of text and the bottom of the StringBox will be
@@ -201,11 +247,11 @@ public class StringBox {
             returnString.append(rows[0].toString());
         }
         for (int i = 1; i < logicalHeight; i++) {
-            returnString.append("\n").append(rows[i].toString());
+            returnString.append(System.lineSeparator()).append(rows[i].toString());
         }
         if (padToHeight) {
             for (int i = logicalHeight; i < maximumHeight; i++) {
-                returnString.append("\n").append(rows[i].toString());
+                returnString.append(System.lineSeparator()).append(rows[i].toString());
             }
         }
         return returnString.toString();