Instead of using fields, translate the reference to two indices; one for the row, the other the column. Your nested list appears to use a list of rows, and each nested list is a list of cards at each column. It could be that your nested list actually encodes columns and that each nested list holds cards at each row, but then you only have to swap the row
and col
variables in one place.
Once you have separate row
and col
variables you can then use those two values to index the nested list:
col, row = interpret_reference(reference)
card = grid[row][col]
where reference
is the user's input. Note that grid[row]
gives you the inner list of columns, and grid[row][col]
then picks the right column.
Python lists are indexed with non-negative integers, so numbers from 0 and up.
So you need a way to translate the letter (a
, b
, c
, d
, e
) to an integer column index starting at 0, and the number (1
, 2
, 3
, 4
) to an integer value one lower, so "1"
becomes 0, etc., an operation defined as a function named interpret_reference()
.
There are lots of ways of doing that. One simple way would be to use a dictionary for both column letters and row numbers:
col_letters = {"a": 0, "b": 1, "c": 2, "d": 3, "e": 4}
row_numbers = {"1", 0, "2": 1, "3": 2, "4": 3}
def interpret_reference(userinput):
col, row = userinput
return col_letters[col], row_numbers[row]
Note that this returns col, row
, the same order as the user input. In my first example code snippet, the variables are then used in the swapped order to index the nested list. If your actual nested list structure is swapped, simply swap the order to grid[col][row]
.
The interpret_reference()
function ignores error handling (where a user enters something that's not a valid reference). The function will raise an exception in that case, either ValueError
when the input is not exactly 2 characters, or KeyError
when they used a character that's not a valid row or column reference. See Asking the user for input until they give a valid response for methods of handling user input with error handling.
There are, as mentioned, other techniques to map the user input to integer numbers.
Computers encode text as numbers. What numbers exactly doesn't really matter, but you can rely on the numbers for lower-case ASCII letters (a, b, c, d, etc.) to be consecutive. The ord()
function gives you the integer number that the Unicode standard has assigned to a character, and if you then subtract the Unicode number (a codepoint) for the character "a"
from that value you get an number starting at 0, provided you started with a lowercase letter:
col = ord(col_reference) - ord("a")
This sets col
to 0
if col_reference
is the character "a"
, 1
, if given "b"
, etc.
You could use the same trick for the number input, when entered on the keyboard in response to a input()
call, Python receives the number part as a string. Subtract such ASCII digits (characters representing the Arabic numerals used in English) from ord("1")
and you get the right row index.
The int()
type can take a string and interpret it as an integer number. Given the string "1"
, it returns the integer value 1
. Subtract 1 and you are done:
row = int(row_reference) - 1
This changes how you handle errors, however; using dictionaries makes it easier to detect incorrect input because only valid input characters are keys in the dictionaries. When using ord()
and int()
, however, you also have to do extra work to validate that the resulting integers are not negative numbers and not too large (so larger than 3 or 4).
E.g. if the user gave you z9
as input, you'd get col = 25
and row = 8
and then you'd get an IndexError
when you tried to use those references. And "99"
would also work as input, giving you col = -40
because the ASCII character "9"
comes before the lowercase letter "a"
in the Unicode table (they have integer codepoint numbers 57 and 97, respectively).
Side note: your create_grid
function changes the cards
list in-place. It is probably fine, as long as your other code doesn't expect the card symbols to stay in their original order. You can replace random.shuffle(cards)
with shuffled = random.sample(cards, len(cards))
to get a new list that is shuffled without affecting the original cards
list.