Problem:I have seen a few questions around hangman. Usually this is done in a very hackish way, which usually can not be generalized any further. My thought or question is about the creation of the gown, which is a central part in any hangman game. I want to create the ASCII image below _____ |   | O   |/|\  |/ \  |     |           ---------- Where one limb of the stick figure should appear each time the function is prompted. I also wanted to be able to specify both the height and width of the gown. However I was not able to scale the stick figure relative to the gown size. The code is provided below and I have two simple questions about it =)Question:Is there a cleaner way to hang the man? I feel my method is very barbaric (I used some black voodo graduate mathematics to get it to look correct).Is there a way to make the stick figure scale with the size of the gown? (essentially providing more guesses). Code:from math import ceildef create_gown(width, height):    gown = []    gown.append('{:>{}s}'.format('_'*int(width/2), 10))    gown.append('{:>{}s} {:>{}s}'.format(        '|', 11 - int(width/2), '|', int(width/2)-2))    for i in range(height-3):        gown.append('{:^{}s}'.format('|', 20))    gown.append('{:^{}s}'.format('-'*width, 20))    return gowndef wrong_answer(gown, attempt=0):    height, width = len(gown), len(gown[-1].strip())    offset1 = int((-width+23)*0.5)+1    offset3 = int(ceil(0.5*(width-7)))    if attempt == 0:        return gown    elif attempt == 1:        new_line = '{:>{}s} {:>{}s}'.format('O', offset1-1, '|', offset3+1)        row = 2    elif attempt == 2:        new_line = '{:>{}s} {:>{}s}'.format('|', offset1-1, '|', offset3+1)        row = 3    elif attempt == 3:        new_line = '{:>{}s} {:>{}s}'.format('/| ', offset1, '|', offset3)        row = 3    elif attempt == 4:        new_line = '{:>{}s} {:>{}s}'.format('/|\\', offset1, '|', offset3)        row = 3    elif attempt == 5:        new_line = '{:>{}s} {:>{}s}'.format('/  ', offset1, '|', offset3)        row = 4    elif attempt == 6:        new_line = '{:>{}s} {:>{}s}'.format('/ \\', offset1, '|', offset3)        row = 4    else:        raise Exception(Ops! The number of attempts must be an integer from 0 to 6.)    gown[row] = new_line    return gowndef print_gown(gown):    for line in gown:        print lineif __name__ == '__main__':    gown = create_gown(10, 7)    print len(gown)    for i in range(7):        gown = wrong_answer(gown, i)        print_gown(gown)
The right way to hang a man
python;python 2.7;hangman;ascii art
RepetitionsAll your elif share the same structure. You just need to ensure that the inserted pattern is always 3 wide and you can drop your offsets adjustments. The logical next step is to use a dictionary to store the pattern and the row for each attempt:_GOWN_MODIFIER = {    1: (' O ', 2),    2: (' | ', 3),    3: ('/| ', 3),    4: ('/|\\', 3),    5: ('/  ', 4),    6: ('/ \\', 4),}def wrong_answer(gown, attempt=0):    height, width = len(gown), len(gown[-1].strip())    offset1 = int((-width+23)*0.5)+1    offset3 = int(ceil(0.5*(width-7)))    if not attempt:        return gown    try:        pattern, row = _GOWN_MODIFIER[attempt]    except KeyError:        raise Exception(Ops! The number of attempts must be an integer from 0 to 6.)    else:        gown[row] = '{:>{}s} {:>{}s}'.format(pattern, offset1, '|', offset3)    return gownCalculusYou do not need ceil nor int to perform an integer division by 2. In Python 2, / is already the operator you need. You can also use // which is also the same operation. The advantage of the latter over the former is that the behaviour is the same in Python 3, whereas / will perform a decimal division in Python 3._GOWN_MODIFIER = {    1: (' O ', 2),    2: (' | ', 3),    3: ('/| ', 3),    4: ('/|\\', 3),    5: ('/  ', 4),    6: ('/ \\', 4),}def wrong_answer(gown, attempt=0):    if not attempt:        return gown    height, width = len(gown), len(gown[-1].strip())    offset1 = (23 - width) // 2 + 1    offset3 = (width - 6) // 2    try:        pattern, row = _GOWN_MODIFIER[attempt]    except KeyError:        raise Exception(Ops! The number of attempts must be an integer from 0 to 6.)    else:        gown[row] = '{:>{}s} {:>{}s}'.format(pattern, offset1, '|', offset3)    return gowndef create_gown(width, height):    half_width = width // 2    gown = []    gown.append('{:>{}s}'.format('_'*half_width, 10))    gown.append('{:>{}s} {:>{}s}'.format(        '|', 11 - half_width, '|', half_width-2))    for i in range(height-3):        gown.append('{:^{}s}'.format('|', 20))    gown.append('{:^{}s}'.format('-'*width, 20))    return gownCreation vs modificationsYou're aware that you can create sequences of repeating elements using seq(element) * count. You can use that to create your gown variable by repeating the pole and then modifying the top two rows and the last one; it should be more memory friendly as the space needed to store the list will be allocated in one go:def create_gown(width, height):    half_width = width // 2    gown = ['{:^{}s}'.format('|', 20)] * height    gown[0] = '{:>{}s}'.format('_' * half_width, 10)    gown[1] = '{:>{}s} {:>{}s}'.format(        '|', 11 - half_width, '|', half_width-2)    gown[-1] = '{:^{}s}'.format('-' * width, 20)    return gownOn modifying in place and returning a valueand a bit about printing tooYour wrong_answer both modifies the gown in place and return the modified value. This is unnecessary as the caller still should hold a reference to the value (which was modified). When calling the code, you can have:gown2 = wrong_answer(gown, attempt=3)but>>> gown2 is gownTrueSo there is really no point in duplicating references to the same object. Instead, what you can do is preprocess the printing job, so you don't really need the print_gown function:def wrong_answer(gown, attempt=0):    height, width = len(gown), len(gown[-1].strip())    offset1 = (23 - width) // 2 + 1    offset3 = (width - 6) // 2    if attempt:        try:            pattern, row = _GOWN_MODIFIER[attempt]        except KeyError:            raise Exception(Ops! The number of attempts must be an integer from 0 to 6.)        else:            gown[row] = '{:>{}s} {:>{}s}'.format(pattern, offset1, '|', offset3)    return '\n'.join(gown)Usage:print(wrong_answer(gown, attempt=3))ExceptionsRaising a generic purpose Exception is bad practice, as it makes the except clauses trying to handle your code being able to catch more than they should. You should at least use a more generic exception (such as ValueError) or define your own:class AlreadyHangedError(ValueError):    passdef wrong_answer(gown, attempt):    ...    raise AlreadyHangedError('...')    ...However, there is something odd in the way you use your wrong_answer: the caller is expected to call this function using increasing attempts. This is the job for a generator. By turning wrong_answer into a generator, you can call it to create a generator instance and then call next on this instance (or let a for loop do it for you) to get the next gown to print:def wrong_answer(width, height):    gown = create_gown(width, height)    offset1 = (23 - width) // 2 + 1    offset3 = (width - 6) // 2    yield '\n'.join(gown)    for attempt in range(1, 7):        pattern, row = _GOWN_MODIFIER[attempt]        gown[row] = '{:>{}s} {:>{}s}'.format(pattern, offset1, '|', offset3)        yield '\n'.join(gown)Usage:for gown in wrong_answer(10, 7):    print(gown)or, in a more real-case scenario:def hangman_game():    for gown in wrong_answer(10, 7):        while True:            status = manage_user_input()            if status == 'FAILED':  # Whatever                break            if status == 'COMPLETED':  # Whatever                return        print gown    print 'You lose'Magic numberscreate_gown seems to center the gown in 20-sized strings, but what if width is greater than that? At first, you should define this value and give it a meaningful name, and same for all values that derive from it; and then, you might want to take max(20, width) as a base for your calculus.