Sorry it may be very basic stuff. I'm new to python and cant put my finger on what's wrong here
I have this dictionary:
Board = {'top-L': ' ', 'top-M': ' ', 'top-R': ' ',
'mid-L': ' ', 'mid-M': ' ', 'mid-R': ' ',
'low-L': ' ', 'low-M': ' ', 'low-R': ' '}
I'm trying to write a function that accepts a number 1-9, convert it to dict keys representing these places and return True if value == ' ':
def CheckSpace(Space): # Will return True if space is available
switcher = {
1: 'top-L',
2: 'top-M',
3: 'top-R',
4: 'mid-L',
5: 'mid-M',
6: 'mid-R',
7: 'low-L',
8: 'low-M',
9: 'low-R',
}
return Board.get(switcher) == ''
Error : TypeError: unhashable type: 'dict'
Can someone give me a tip please?
***edit
I guess i can write that function like this:
def CheckSpace(Space):#Will return True if space is available
if space == 1:
place = Board.get('top-L')
if space == 2:
place = Board.get('top-M')
if space == 3:
place = Board.get('top-R')
if space == 4:
place = Board.get('mid-L')
#.... and so on to 9..
return place
But I'm trying to use something equivalent to switch case
Board.get(switcher) == ''
switcher is a dict. Maybe you want Board.get(switcher.get(Space)) == ' '
The .get method accepts a key. You passed in switcher which is a dictionary (dicts are not hashable, hence the error).
Get the key first using .get;
E.g. switcher.get(Space)
And then: Board.get(switcher.get(Space)) == ' '
Related
total begginner here.
I am trying to write a complete tic-tac-toe program based on the automate boring stuff exercise. I got it working before like this:
theBoard = {'top-L': ' ', 'top-M': ' ', 'top-R': ' ',
'mid-L': ' ', 'mid-M': ' ', 'mid-R': ' ',
'low-L': ' ', 'low-M': ' ', 'low-R': ' '}
def printBoard(board): #function to print board
print(board['top-L'] + '|' + board['top-M'] + '|' + board['top-R'])
print('-+-+-')
print(board['mid-L'] + '|' + board['mid-M'] + '|' + board['mid-R'])
print('-+-+-')
print(board['low-L'] + '|' + board['low-M'] + '|' + board['low-R'])
print('''
Hi! This is my tic-tac-toe text based game.
To make your move, write where you want to play:
top-L top-M top-R
mid-L mid-M mid-R
low-L low-M low-R
''')
turn= 'X' #starting
while True:
printBoard(theBoard)
print(f'Turn for {turn}. Where will you play?')
try:
move = input()
if theBoard[move] == ' ':
theBoard[move] = turn
if turn == 'X':
turn = 'O'
else:
turn = 'X'
else:
print('That move is not possible!')
continue
except KeyError:
print('''Wrong input.
To make your move, write where you want to play:
top-L top-M top-R
mid-L mid-M mid-R
low-L low-M low-R
''')
continue
if ((theBoard['top-L']==theBoard['top-M']==theBoard['top-R']) and theBoard['top-L']!=' ')\
or ((theBoard['mid-L']==theBoard['mid-M']==theBoard['mid-R']) and theBoard['mid-R']!=' ')\
or ((theBoard['low-L']==theBoard['low-M']==theBoard['low-R']) and theBoard['low-L']!=' ')\
or ((theBoard['top-L']==theBoard['mid-M']==theBoard['low-R']) and theBoard['top-L']!=' ')\
or ((theBoard['low-L']==theBoard['mid-M']==theBoard['top-R']) and theBoard['low-L']!=' ')\
or ((theBoard['top-L']==theBoard['mid-L']==theBoard['low-L']) and theBoard['top-L']!=' ')\
or ((theBoard['top-M']==theBoard['mid-M']==theBoard['low-M']) and theBoard['top-M']!=' ')\
or ((theBoard['top-R']==theBoard['mid-R']==theBoard['low-R']) and theBoard['top-R']!=' '):
break
if turn == 'X':
turn = 'O'
else:
turn = 'X'
print(f'Good Job {turn}, you won!')
This worked well and i turned to codereview for some improvements.
I stored the strings 'X' and 'O' as I discovered that those were considered magic strings and make my code less clean.
Next, I wanted to store all the win conditions in a variable called conditions. But when I do this my program will now not get out of the loop when I get a winning move. Why could this be?
theBoard = {'top-L': ' ', 'top-M': ' ', 'top-R': ' ',
'mid-L': ' ', 'mid-M': ' ', 'mid-R': ' ',
'low-L': ' ', 'low-M': ' ', 'low-R': ' '}
def printBoard(board):
print(board['top-L'] + '|' + board['top-M'] + '|' + board['top-R'])
print('-+-+-')
print(board['mid-L'] + '|' + board['mid-M'] + '|' + board['mid-R'])
print('-+-+-')
print(board['low-L'] + '|' + board['low-M'] + '|' + board['low-R'])
conditions = (((theBoard['top-L'] == theBoard['top-M'] == theBoard['top-R']) and theBoard['top-L'] != ' ') \
or ((theBoard['mid-L'] == theBoard['mid-M'] == theBoard['mid-R']) and theBoard['mid-R'] != ' ') \
or ((theBoard['low-L'] == theBoard['low-M'] == theBoard['low-R']) and theBoard['low-L'] != ' ') \
or ((theBoard['top-L'] == theBoard['mid-M'] == theBoard['low-R']) and theBoard['top-L'] != ' ') \
or ((theBoard['low-L'] == theBoard['mid-M'] == theBoard['top-R']) and theBoard['low-L'] != ' ') \
or ((theBoard['top-L'] == theBoard['mid-L'] == theBoard['low-L']) and theBoard['top-L'] != ' ') \
or ((theBoard['top-M'] == theBoard['mid-M'] == theBoard['low-M']) and theBoard['top-M'] != ' ') \
or ((theBoard['top-R'] == theBoard['mid-R'] == theBoard['low-R']) and theBoard['top-R'] != ' '))
print('''
Hi! This is my tic-tac-toe text based game.
To make your move, write where you want to play:
top-L top-M top-R
mid-L mid-M mid-R
low-L low-M low-R
''')
playerX = 'X'
playerO = 'O'
turn= playerX
while True:
printBoard(theBoard)
print(f'Turn for {turn}. Where will you play?')
try:
move = input()
if theBoard[move] == ' ':
theBoard[move] = turn
if turn == playerX:
turn = player0
else:
turn = playerX
else:
print('That move is not possible!')
continue
except KeyError:
print('''Wrong input.
To make your move, write where you want to play:
top-L top-M top-R
mid-L mid-M mid-R
low-L low-M low-R
''')
continue
if conditions == True:
printBoard(theBoard)
break
if turn == playerX:
turn = player0
else:
turn = playerX
print(f'Good Job {turn}, you won!')
That is because conditions is a bool value. It is calculated when it is set. That is to say - it not a function that makes its computations when it is called. In your case conditions is set to False and it will remain to be False. It is a constant.
Wrap it in a function like this:
def check():
conditions = (((theBoard['top-L'] == theBoard['top-M'] == theBoard['top-R']) and theBoard['top-L'] != ' ') \
or ((theBoard['mid-L'] == theBoard['mid-M'] == theBoard['mid-R']) and theBoard['mid-R'] != ' ') \
or ((theBoard['low-L'] == theBoard['low-M'] == theBoard['low-R']) and theBoard['low-L'] != ' ') \
or ((theBoard['top-L'] == theBoard['mid-M'] == theBoard['low-R']) and theBoard['top-L'] != ' ') \
or ((theBoard['low-L'] == theBoard['mid-M'] == theBoard['top-R']) and theBoard['low-L'] != ' ') \
or ((theBoard['top-L'] == theBoard['mid-L'] == theBoard['low-L']) and theBoard['top-L'] != ' ') \
or ((theBoard['top-M'] == theBoard['mid-M'] == theBoard['low-M']) and theBoard['top-M'] != ' ') \
or ((theBoard['top-R'] == theBoard['mid-R'] == theBoard['low-R']) and theBoard['top-R'] != ' '))
return conditions
And call this function instead of conditions in the if statement:
if check() == True:
printBoard(theBoard)
break
I wrote some code for a Python homework assignment and it's running fine in Mu-editor and other IDE's, but not in the Atom editor (using the Hydrogen package to run it), where it gives me an unexpected NameError. I've already posted this issue in the Atom Github, but I'm not getting a response. The code:
theBoard = {'top-L': ' ', 'top-M': ' ', 'top-R': ' ',
'mid-L': ' ', 'mid-M': ' ', 'mid-R': ' ',
'low-L': ' ', 'low-M': ' ', 'low-R': ' '}
def printBoard(board):
print(board['top-L'] + '|' + board['top-M'] + '|' + board['top-R'])
print('-+-+-')
print(board['mid-L'] + '|' + board['mid-M'] + '|' + board['mid-R'])
print('-+-+-')
print(board['low-L'] + '|' + board['low-M'] + '|' + board['low-R'])
turn = 'X'
for i in range(9):
printBoard(theBoard)
print('Turn for ' + turn + '. Move on which space?')
move = input()
theBoard[move] = turn
if turn == 'X':
turn = 'O'
else:
turn = 'X'
printBoard(theBoard)
The NameError I get when trying to run this code:
----> 1 printBoard(theBoard)
NameError: name 'theBoard' is not defined
It throws this error in line 1 of the for loop printBoard(theBoard)
I've played around with formatting and shortening theBoard in case the formatting of the dictionary was the problem, but that did not change anything. theBoard is stored in the global scope (right?), so printBoard should be able to call it in the for loop.
Does anybody have an idea why this is happening?
I've just started learning and I've only learnt the basics but this is my current code. I need to put it in a loop and ask the user to place the number for up to 8 times.
num_list = ['1','2','3','4','5',]
import random
num = random.choice(num_list)
table = [[' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ']]
ss = {"W1":[0,0],
"W2":[1,0],
"W3":[2,0],
"W4":[3,0],
"X1":[0,1],
"X2":[1,1],
"X3":[2,1],
"X4":[3,1],
"Y1":[0,2],
"Y2":[1,2],
"Y3":[2,2],
"Y4":[3,2],
"Z1":[0,3],
"Z2":[1,3],
"Z3":[2,3],
"Z4":[3,3]}
ans = input('where would you like to place it: ')
index_ = ss[ans][0]
columns_ = ss[ans][1]
table[index_][columns_] = num
print(table)
This code below here is supposed to make sure the user is placing the number adjacent to another number.
How do I make sure it only starts to check on the 2nd turn onwards? And how do I get it to repeat the turn if it is not adjacent? I also wanted to put the code above into functions and call it at the end to make it neater but I'm not sure what to put in and what to not.
def moveandclip(n, x, y):
n[0] = max(0, min(n[0] + x, 3))
n[1] = max(0, min(n[1] + y, 3))
return n
above = moveandclip(ss[ans], 0 ,1)
below = moveandclip(ss[ans], 0 ,-1)
left = moveandclip(ss[ans], -1 ,0)
right = moveandclip(ss[ans], 1 ,0)
if above == '' and below == '' and left == '' and right == '':
print('It must be placed adjacent to another number.')
repeat the turn
else:
continue to next turn
If you want to run the code 8 times, you can do like this:
def moveandclip(n, x, y):
n[0] = max(0, min(n[0] + x, 3))
n[1] = max(0, min(n[1] + y, 3))
return n
above = moveandclip(ss[ans], 0 ,1)
below = moveandclip(ss[ans], 0 ,-1)
left = moveandclip(ss[ans], -1 ,0)
right = moveandclip(ss[ans], 1 ,0)
for _ in range(8):
if above == '' and below == '' and left == '' and right == '':
print('It must be placed adjacent to another number.')
else:
# Do whatever you want to
# Add more code if you want to run some more statements regardless of the condition
while True:
# Turn code
if above == '' and below == '' and left == '' and right == '':
print('It must be placed adjacent to another number.')
else:
break
So I am trying to create a very simple 1-player battleship game in python. Where the computer randomly places its ships in the rows and columns, and the player guesses which row and column a ship is in. My current problem is that my code does that, however it prints the board out each time and also seems to make the choices for the player as well.
import random
#Make board
board = [
[' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' '],
]
# List to refer to columns by letter, since that is how a typical battleship game is
#initiated
letters2Numbers = {
'A': 0,
'B': 1,
'C': 2,
'D': 3,
'E': 4,
}
#Function to ask the user for their board position
def generateShips():
for a in range (0,55):
row = random.randrange(1,6)
column = random.choice(['A','B','C','D','E'])
rowNumber = row
columnNumber = column
return int(row) - 1, letters2Numbers[column]
def askUser():
column = input("column (A to E):")
while column not in "ABCDE":
print("That column is wrong! It should be A, B, C, D or E")
column = input("column (A to E):")
row = input("row (1 to 5):")
while row not in "12345":
print("That row is wrong! it should be 1, 2, 3, 4 or 5")
row = input("row (1 to 5):")
return int(row) - 1, letters2Numbers[column]
def printBoard(board):
# Shows the board, one row at a time, labelled
print(" A B C D E")
print(" +-+-+-+-+-+")
rowNumber = 1
for row in board:
print("%d|%s|" % (rowNumber, "|".join(row)))
print(" +-+-+-+-+-+")
rowNumber = rowNumber + 1
# Now clear the screen, and the other player starts guessing
print("\n"*50)
guessesBoard = [
[' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' '],
]
# Keep playing until we have 5 right guesses
guesses = 0
while guesses < 5:
print("Guess a battleship location")
rowNumber, columnNumber = askUser()
if guessesBoard[rowNumber][columnNumber] != ' ':
print("You have already guessed that place!")
continue
# Check that there are no repeats
if board[rowNumber][columnNumber] == 'X':
print("HIT!")
guessesBoard[rowNumber][columnNumber] = 'X'
guesses = guesses + 1
else:
guessesBoard[rowNumber][columnNumber] = '.'
print("MISS!")
printBoard(guessesBoard)
print("GAME OVER!")
This is my code so far. If you run it, you'll see the error I'm talking about.
You never ask the player for choices; you print a message suggesting that you're about to do so, but then your code charges ahead and uses the row and column from ship generation. Nowhere in your program do you accept user input.
You want to use function input() rather than random.SOMETHING. Then your input will not be choosen by PC.
Then to convert user input (which always returns a string) to a number, you can use something like:
a = input("perhaps a number: ")
if not a.isdigit():
raise ValueError("I said number :(")
a = int(a)
You probably don't want to raise the error, I am just demonstrating what you can build on.
I am waiting for further development of this question. :)
I am fairly new to programming, and python is my first language. I am learning on my own so maybe I am missing something. Sorry, if I could not word my problem properly.
I have written a function that accepts any number between 0-99 and converts it into mandarin based on a dictionary. Here is the function:
trans = {'0':'ling', '1':'yi', '2':'er', '3':'san', '4': 'si','5':'wu', '6':'liu', '7':'qi', '8':'ba', '9':'jiu', '10': 'shi'}
def convert_to_mandarin(us_num, flag = True):
'''
us_num, a string representing a US number 0 to 99
returns the string mandarin representation of us_num
'''
if len(us_num) == 1:
if us_num != '0':
return trans[us_num]
elif flag:
return trans[us_num]
else:
return '\b'
elif len(us_num) > 1:
if us_num[0] == '1':
return trans['10'] +' '+ convert_to_mandarin(us_num[1:], False)
else:
return trans[us_num[0]] + ' ' + trans['10'] + ' ' + convert_to_mandarin(us_num[1:], False)
else:
return convert_to_mandarin(us_num[:-1], False) + trans[us_num[-1]]
But for number ending with 0, the string is being returned with a trailing space. For example if n = convert_to_mandarin('10') then it returns n = 'shi '
but I want it to be n = 'shi'
So how can I get rid of the trailing space?
you insert a space and try to delete it using backspace. But that is no good in files or debug.
Don't return anything where you returned the backspace, and strip the added strings afterwards to get rid of trailing spaces using str.rstrip:
trans = {'0':'ling', '1':'yi', '2':'er', '3':'san', '4': 'si','5':'wu', '6':'liu', '7':'qi', '8':'ba', '9':'jiu', '10': 'shi'}
def convert_to_mandarin(us_num, flag = True):
'''
us_num, a string representing a US number 0 to 99
returns the string mandarin representation of us_num
'''
if len(us_num) == 1:
if us_num != '0':
return trans[us_num]
elif flag:
return trans[us_num]
else:
return ''
elif len(us_num) > 1:
if us_num[0] == '1':
return (trans['10'] +' '+ convert_to_mandarin(us_num[1:], False)).rstrip()
else:
return (trans[us_num[0]] + ' ' + trans['10'] + ' ' + convert_to_mandarin(us_num[1:], False)).rstrip()
else:
return convert_to_mandarin(us_num[:-1], False) + trans[us_num[-1]]
(sometimes a post-correction is easier than trying to figure out how to avoid the problem, specially with recursion. Note that rstrip returns the same string if no replacement done, so the overhead is negligeable)