@staticmethod
def grid_pos_input(height, width, question='Enter a Position:'):
    "\n        Take user-input in coordinate form.\n\n        The input question will be repeated until valid input is given.\n        The input must be a valid coordinate in battleship form (r'[A-Z]\\d+').\n        The input coordinate must be inside of the grid defined by height and width.\n\n        Parameters\n        ----------\n        height : int\n            Specifies the height of the grid.\n        width : int\n            Specifies the width of the grid.\n        question : str, optional\n            String to be displayed as the input question. Will be boxed with Utils#box_string before printing. Defaults to 'Enter a Position'.\n\n        Returns\n        -------\n        tuple\n            Contains the following:\n                int\n                    Height-aligned position (y-position) of input.\n                int\n                    Width-aligned position (x-position) of input.\n        "
    error = ''
    while True:
        Utils.box_string(((error + '\n') + question).strip(), print_string=True)
        loc = input().upper()
        if (not fullmatch('[A-Z][1-2]?[0-9]', loc)):
            error = 'ERROR: Invalid input! Input string is not a valid coordinate! Please try again.'
            continue
        elif ((loc[0] in letters[:height]) and (0 < int(loc[1:]) <= width)):
            return (letters.index(loc[0]), (int(loc[1:]) - 1))
        else:
            error = 'ERROR: Invalid input! Input string is not in the grid! Please try again.'
            continue
Take user-input in coordinate form.

The input question will be repeated until valid input is given.
The input must be a valid coordinate in battleship form (r'[A-Z]\d+').
The input coordinate must be inside of the grid defined by height and width.

Parameters
----------
height : int
    Specifies the height of the grid.
width : int
    Specifies the width of the grid.
question : str, optional
    String to be displayed as the input question. Will be boxed with Utils#box_string before printing. Defaults to 'Enter a Position'.

Returns
-------
tuple
    Contains the following:
        int
            Height-aligned position (y-position) of input.
        int
            Width-aligned position (x-position) of input.
@staticmethod
def grid_pos_input(height, width, question='Enter a Position:'):
    "\n        Take user-input in coordinate form.\n\n        The input question will be repeated until valid input is given.\n        The input must be a valid coordinate in battleship form (r'[A-Z]\\d+').\n        The input coordinate must be inside of the grid defined by height and width.\n\n        Parameters\n        ----------\n        height : int\n            Specifies the height of the grid.\n        width : int\n            Specifies the width of the grid.\n        question : str, optional\n            String to be displayed as the input question. Will be boxed with Utils#box_string before printing. Defaults to 'Enter a Position'.\n\n        Returns\n        -------\n        tuple\n            Contains the following:\n                int\n                    Height-aligned position (y-position) of input.\n                int\n                    Width-aligned position (x-position) of input.\n        "
    error = 
    while True:
        Utils.box_string(((error + '\n') + question).strip(), print_string=True)
        loc = input().upper()
        if (not fullmatch('[A-Z][1-2]?[0-9]', loc)):
            error = 'ERROR: Invalid input! Input string is not a valid coordinate! Please try again.'
            continue
        elif ((loc[0] in letters[:height]) and (0 < int(loc[1:]) <= width)):
            return (letters.index(loc[0]), (int(loc[1:]) - 1))
        else:
            error = 'ERROR: Invalid input! Input string is not in the grid! Please try again.'
            continue