使用显式循环编写内容通常会导致难以调试的问题。这就是为什么 Python 不强迫你这样做,实际上鼓励你不要:
def display(theMap):
print("PLAYER MAP")
for row in theMap:
for col in row:
print(col)
print()
print()
这仍然不是您真正想要的,因为会print(col)
打印一个换行符。您不希望每个单元格单独一行,您希望单元格之间有空格,并且每一行单独一行。要做到这一点,你必须print(col, end=' ')
改为。
或者,更简单地说:
def display(theMap):
print("PLAYER MAP")
for row in theMap:
print(' '.join(row))
print()
或者,更简洁——但可能不那么简单:
def display(theMap):
print("PLAYER MAP")
print('\n'.join(' '.join(row) for row in theMap))
print()
您可以类似地改进 theMap,只需一次创建 theMap,而不是创建空行,然后替换它们。例如:
def loadMap():
return [
("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J"),
("-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-"),
("|r|","| |", "| |", "| |", "| |", "| |", "| |", "| |", "| |", "| |", "|"),
("-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-")]
一般来说,每当你发现自己for i in range(something)
在用 Python 编写代码时,你都在做一些不必要的事情,最终你只是要调试。
现在,您可以争辩说这种风格不会“捕捉错误”。但是使用显式循环执行的操作只能捕获少数错误,并且以一种很难调试的方式捕获它们。如果你知道你的先决条件,你通常可以更简单、更清楚地写出来:
theMap = loadMap()
assert(all(len(row) == len(theMap[0]) for row in theMap))
此外,如果您知道测试用例的输出应该是什么,您可以编写单元测试来验证输出。
无论如何,即使解决了所有这些问题,您仍然会遇到一些问题。例如,除了第 2 行比其他行短几列之外,该行中的各个列是其他行中的列的 3 倍,因此它根本不会对齐。但是一旦你让它运行起来,调试可视化的东西应该会更容易。
退后一步,您显然将通过第 2 行推进“r”。事实上,您可能需要表示地图的只是宽度和当前位置:
def display(mapWidth, playerPosition):
print('PLAYER MAP')
# Display the first line. This is the header, with a label for each of the
# mapWidth columsn, with a space between each label, and an extra space at
# the start, like ' 0 1 2 3 4'. The ' '.join(s) creates a new string by
# putting a space between each element of s. The '012...XYZ'[:mapWidth]
# just takes the first mapWidth characters of the longer string.
print(' ' + ' '.join('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'[:mapWidth]))
# Display the second line. This is just a '-' for each column, with a space
# between each, and an extra space at the start, like ' - - - - -'. The join
# works the same as above; the '-' * mapWidth creates a string with mapWidth
# copies of '-'.
print(' ' + ' '.join('-' * mapWidth))
# Display the third line. This is the trickiest. This is cell for each column,
# where the first playerPosition cells are '| |', the playerPositionth is
# '|r|', and the rest are again '| |', with no space between them. It seemed
# simpler to treat this as a group of playerPosition+1 '|' characters with
# spaces between, an 'r' character, and a group of mapWidth-playerPosition
# '|' characters with spaces between again, but there are various different
# ways of printing something equivalent. The only new thing here is the
# end='' keyword argument--without that, each print ends with a newline.
print(' '.join('|' * (playerPosition + 1)), end='')
print('r', end='')
print(' '.join('|' * (mapWidth - playerPosition)))
# Fourth line, same as the second.
print(' ' + ' '.join('-' * mapWidth))
print()
您可能会发现这更容易阅读,具体取决于您对join
方法、print
函数等的熟悉程度:
def display(mapWidth, playerPosition):
print('PLAYER MAP')
print(' ' + ' '.join('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'[:mapWidth]))
print(' -' * mapWidth)
print(' '.join('|' * (playerPosition + 1)) +
'r' +
' '.join('|' * (mapWidth - playerPosition)))
print(' -' * mapWidth)
print()
值得思考为什么,例如,' ' + ' '.join('-' * 8)
与' -' * 8
.
完成棘手的第三行的另一种方法是:
# Print mapWidth '|' characters, each followed by a ' ', except for the one
# at the player position, which is followed by an 'r'. Then we still need one
# more '|' at the end.
print(''.join('|' + (' ' if i != playerPosition else 'r')
for i in range(mapWidth) + '|')
我认为这是用英语解释的最简单的方法,但是将其翻译成 Python 需要生成器表达式和三元 if 表达式,这两者你可能还不想学习——最终结果甚至是 Python 的经验开发人员可能不想阅读。
当然,如果有疑问,您可以随时将内容提取到单独的行,甚至单独的函数中,以使它们更具可读性:
cellsBeforePlayer = '| ' * playerPosition
cellsWithPlayer = cellsBeforePlayer + '|r|'
cellsToEnd = cellsWithPlayer + '| ' * (mapWidth - playerPosition)
print(cellsToEnd)
无论如何,这些都做同样的事情:
>>> display(MAX_COLUMN - MIN_COLUMN + 1, 3)
PLAYER MAP
0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J
- - - - - - - - - - - - - - - - - - - -
| | | |r| | | | | | | | | | | | | | | | |
- - - - - - - - - - - - - - - - - - - -
除非这些MIN_COLUMN
和MAX_COLUMN
值是要求的一部分,否则我会使用单个COLUMNS=20
变量来代替 - 再次,它避免了另一个常见的一对一错误(+ 1
在函数调用中,在需要时很容易忘记包含,或者不需要时添加不正确)。
或者,如果地图宽度是固定的,那就更简单了:
def display(playerPosition):
print('PLAYER MAP')
print(' ' + ' '.join('0123456789ABCDEFGHIJ'))
print(' -' * 20)
print(' '.join('|' * (playerPosition + 1)) +
'r' +
' '.join('|' * (20 - playerPosition)))
print(' -' * 20)
print()
无论如何,这样做的好处不仅仅是简单display
而且根本不需要loadMap
移动玩家,而不是这样:
theMap[2][playerPosition] = '| |'
playerPosition += stepsMoved
theMap[2][playerPosition] = '|r|'
display(theMap)
你只需这样做:
playerPosition += stepsMoved
display(playerPosition)
你的整个游戏状态从一个复杂的列表列表减少到一个整数。