I'm new to learning Python and have enough under my belt to start attempting a beginner's Tic-Tac-Toe program.
My issue is thus: I want to have a generic input function called getInput() which will get input from the user, strip trailing white space from that input, and THEN, if a function was passed to it via the optional parameter "specialTest", getInput() will run the input through this provided function and return the output which the specialTest function spat out.
Sometimes this specialTest function will need additional arguments besides the user input. Assume for my purposes that the user input will always be the first argument and is required, and that any additional args will come afterwards.
I tried to implement this situation via *args, and I got it working if the specialTest function had no additional arguments. But the first time I try to feed it additional arguments, it fails.
So for example, getInput("Age?", specialTest=int) works. It prompts for user input and feeds it through the int() function, finally returning the output as an integer. But when I try to pass getInput() a function which has an additional argument - an ordered dictionary which contains strings as keys and dictionaries as values - the program fails with TypeTypeError: getInput() got multiple values for argument 'specialTest'. What needs to be adjusted to get this working as intended?
Code:
import collections
def getInput(msg, specialTest=None, *TestArgs):
"""Get user input and export to the desired format."""
while True:
string = input(msg + ' ').strip()
# If the user passed a function to the SpecialTest parameter,
# pass the user input through that function and return its value.
# If the SpecialTest function returns False or we hit an error,
# that means the input was invalid and we need to keep looping
# until we get valid input.
if specialTest:
try:
string = specialTest(string, *TestArgs)
if string is False: continue
except:
continue
return string
def nametoMove(name, board):
"""Convert player's move to an equivalent board location."""
location = {name: theBoard.get(name)}
# return false if the location name isn't present on the board
if location[name] is None:
return False
return location
# ---Tic-Tac-Toe routine---
# fill the board
row_name = ('top', 'mid', 'lower')
col_name = ('left', 'center', 'right')
theBoard = collections.OrderedDict()
size = 3 # 3x3 board
for x in range(size):
for y in range(size):
key = row_name[x] + ' ' + col_name[y]
value = {'row': x, 'col': y}
theBoard.update({key: value})
# get player's desired board symbol
playerSymbol = getInput("X's or O's?")
# get player's age
playerAge = getInput("Age?", specialTest=int)
# get player's move and convert to same format as theBoard object
# e.g., "top left" --> {'top left': {'row': 0, 'col': 0}}
playerMove = getInput("Move?", specialTest=nametoMove, *theBoard)
*theBoard) after keyword arguments (specialTest=nametoMove). ChangespecialTest=nametoMoveto justnametoMoveand it'll work.specialTestto look like? That is, do you want it to bespecialTest('top', 'left', 2)or what? It looks like you're trying to pass keyword arguments (sincetheBoardis a dictionary) but then your keys have spaces in them.getInput ("Move?", specialTest=nametoMove, *theBoard)—instead of multiple separate values, you probably don't want*argsat all. Just take a sequence called, say,specialArgsas a plain-old argument, and passtheBoardas-is instead of*theBoard. (This has the added advantage that you can usespecialArgsas a keyword in calling the function.)theBoardis anOrderedDict. While you can splat that with*theBoard, what you're doing is passing just the keys, as positional arguments, not the key-value pairs as keyword arguments. Is that what you wanted?nametoMove("top left", theBoard))will return{'top left': {'row': 0, 'col': 0}}because the value which matches the "top left" key in theBoard dictionary is{'row': 0, 'col': 0}