How to call attributes from outside classes? - python

Updated 2.0
Currently updated it so every old "function" has been moved beneath my class. Now it seems like one of my only problems is figuring out all these drawBoard() takes 1 positional argument but 2 were given
This is just the start of my current class, just to show you what I am currently dealing with

Update based on:
Every run of the program will give the option which size the board
should be ...
every board in the code shall be the same size
We make size a class variable and only prompt for a size if it isn't already set. All subsequent board creations will use the same size as the first board:
class BoardHandler:
size = None
def __init__(self):
self.board = None
if BoardHandler.size is None:
self.ask_size()
self.getNewBoard()
def ask_size(self): # no self use, method could be a function
while True:
try:
BoardHandler.size = int(input("Which size would you want? "))
break
except ValueError:
print("Wrong! try again")
def getNewBoard(self):
self.board = []
for _ in range(BoardHandler.size):
self.board.append([' '] * BoardHandler.size)
def resetBoard(self):
for x in range(BoardHandler.size):
for y in range(BoardHandler.size):
self.board[x][y] = ' '
n = int(BoardHandler.size / 2 - 1)
self.board[n][n] = 'B'
self.board[n + 1][n] = 'W'
self.board[n][n + 1] = 'W'
self.board[n + 1][n + 1] = 'B'
def drawBoard(self):
HLINE = ' ' + '-' * (4 * BoardHandler.size) + '-'
print(HLINE)
for y in range(BoardHandler.size):
print("{:2d}".format(y + 1), end=' ')
for x in range(BoardHandler.size):
print('| {}'.format(self.board[x][y]), end=' ')
print('|')
print(HLINE)
handler = BoardHandler()
handler.resetBoard()
handler.board[0][0] = 'W'
handler.drawBoard()
print(BoardHandler.size)
handler2 = BoardHandler()
handler2.drawBoard() # empty board but same size as first

As I said in a comment, I think you should make the two functions in methods of class BoardHandler. This will give you better encapsulation and it's fairly easy to do, here's how:
class BoardHandler:
def __init__ (self, size, board):
self.size = size
self.board = board
def ask_size(self):
try:
self.size = int(input("Which size would you want?"))
except ValueError:
print("Wrong! try again")
ask_size()
def getNewBoard(self):
board=[]
for i in range(self.size):
board.append([' ']* self.size)
self.board = board
def resetBoard(self):
for x in range(self.size):
for y in range(self.size):
self.board[x][y] = ' '
n=int(size/2-1)
self.board[n][n] = 'B'
self.board[n+1][n] = 'W'
self.board[n][n+1] = 'W'
self.board[n+1][n+1] = 'B'
def drawBoard(self):
HLINE = ' ----------------------------------------'
for y in range(self.size):
print(y+1, end=' ')
for x in range(Q):
print('| %s' % (self.board[x][y]), end=' ')
print('|')
print(HLINE)
If you want to keep them outside the class for some reason, you will need to modify each of them to accept a BoardHandler class instance as an argument:
def resetBoard(board_handler):
for x in range(board_handler.size):
for y in range(board_handler.size):
board_handler.board[x][y] = ' '
n=int(board_handler.size/2-1)
board[n][n] = 'B'
board[n+1][n] = 'W'
board[n][n+1] = 'W'
board[n+1][n+1] = 'B'
def drawBoard(board_handler):
HLINE = ' ----------------------------------------'
for y in range(board_handler.size):
print(y+1, end=' ')
for x in range(Q):
print('| %s' % (board_handler.board[x][y]), end=' ')
print('|')
print(HLINE)
This assumes your program creates a single BoardHandler class instance, and does all operations to that object.

Related

I try to do a TicTacToe project myself, but the py close after i enter the very first input

the window of game.py I try out some of the python beginner project to practise my sense of coding.
And after i followed the youtube video step by step, i started to debug and play the
TicTacToe. It closed right after i input my first square/input. But i don't understand
where it goes wrong. I just start fighting with coding, i don't mind to get slap right out
of my face right now. Please, go easy on me. It keeps drive me to the wall.
#Player.py ||||
import math
import random
class Player:
def __init__(self,letter):
self.letter = letter
def get_move(self,game):
pass
class RandomComputerPlayer(Player):
def __init__(self, letter):
super().__init__(letter)
def get_move(self,game):
square = random.choice(game.available_moves())
return square
class HumanPlayer(Player):
def __init__(self, letter):
super().__init__(letter)
def get_move(self,game):
valid_square = False
val = None
while not valid_square:
square = input(self.letter + '\'s turn. Input move (0-8):')
try:
val = int(square)
if val not in game.available_moves():
raise ValueError
valid_square = True
except ValueError:
print('Invalid square. Try again.')
return val
And here's game.py:
#game.py ||||
import time
from player import HumanPlayer, RandomComputerPlayer
class TicTacToe:
def __init__(self):
self.board = [' ' for _ in range(9)]
self.current_winner = None
def print_board(self):
for row in [self.board[i*3:(i+1)*3] for i in range(3)]:
print('| ' + ' | ' .join(row) + ' |')
#staticmethod
def print_board_nums():
# 0 | 1 | 2 etc
number_board = [[str(i) for i in range(j*3, (j+1)*3)] for j in range (3)]
for row in number_board:
print('| ' + ' | '.join(row) + ' |')
def available_moves(self):
moves = []
for (i, x) in enumerate(self.board):
if spot == ' ':
moves.append(i)
def empty_squares(self):
return ' ' in self.board
def num_empty_squares(self):
return len(self.available_moves())
def make_move(self, square, letter):
if self.board[square] == ' ':
self.board[square] = letter
if self.winner(square, letter):
self.current_winner = letter
return True
return False
def winner(self, square, letter):
# winner if 3 in a row anywhere, check all of the possiblity
row_ind = square // 3
row = self.board[row_ind*3 : (row_ind + 1) * 3]
if all ([spot == letter for spot in row]):
return True
col_ind = square % 3
column = [self.board[col_ind + i*3] for i in range(3)]
if all ([spot == letter for spot in column]):
return True
# check diagonals
if square % 2 == 0:
diagonal1 = [self.board[i] for i in[0,4,8]]
if all ([spot == letter for spot in diagonal1]):
return True
diagonal2 = [self.board[i] for i in[2,4,6]]
if all ([spot == letter for spot in diagonal2]):
return True
# if all of the possibility not happen
return False
def play(game, x_player, o_player, print_game = True):
# returns the winner of the game! or None for a tie
if print_game:
game.print_board_nums()
letter = 'X'
while game.empty_squares():
if letter == '0':
square = o_player.get_move(game)
else:
square = x_player.get_move(game)
if game.make_move(square, letter):
if print_game:
print(letter + ' makes a move to square {square}')
game.print_board()
print('') # empty line
if game.current_winner:
if print_game:
print(letter + 'wins!')
return letter
letter = 'O' if letter == 'X' else 'X'
# if letter == 'X':
# letter = 'O'
# else:
# letter = 'X'
time.sleep(0.8)
if print_game:
print('It\'s a tie!')
if __name__ == '__main__':
x_player = HumanPlayer('X')
o_player = RandomComputerPlayer('O')
t = TicTacToe()
play(t, x_player, o_player, print_game = True)
When I copied the code and ran it locally on my computer, the traceback showed that there was an error in game.py, specifically in your available_moves() function.
def available_moves(self):
moves = []
for (i, x) in enumerate(self.board):
if spot == ' ':
moves.append(i)
The traceback specifically says, NameError: name 'spot' is not defined, which is true since spot is not defined. I am assuming spot and x are supposed to mean the same here since you are looking at the square on your Tic-Tac-Toe board. Also, this function should probably return moves; otherwise, any other function calling available_moves() is going to get a value of type None instead of the list of available moves.
def available_moves(self):
moves = []
# iterate through all spots on board
for (i, spot) in enumerate(self.board):
# if a spot is empty, add its index to moves
if spot == ' ':
moves.append(i)
return moves
Also I've been absolutely crushing myself against myself playing this game so thanks for that!
Edit: Just noticed after posting this that Tim Roberts basically summed up my answer. Oops.

Issue checking input type in Pyton 2.7 vs Python 3

I need to re-use a script I wrote in Python 3.10 using Python 2.7; when I change the interpreter to 2.7, script below errors with following message: TypeError: unbound method CheckInput() must be called with Elem instance as first argument (got int instance instead)
Trying to resolve this for hours but I'm a beginner and am definitely missing something. Aim of the program is to add a few values as user input and later on print them out. Code below:
class Elem():
Elem_count = 0
def CheckInput(input):
try:
# Convert it into integer
val = int(input)
except ValueError:
try:
# Convert it into float
val = float(input)
except ValueError:
print("You have entered a string, please use numbers!")
def Add_Elem(self):
if Elem.Elem_count == 0:
print('Enter first Elem info:')
self.width = input('width: ')
Elem.CheckInput(self.width)
self.height = input('Height: ')
Elem.CheckInput(self.height)
self.depth = input('depth: ')
Elem.CheckInput(self.depth)
else:
print('Enter second Elem info:')
self.width = input('width: ')
Elem.CheckInput(self.width)
self.height = input('Height: ')
Elem.CheckInput(self.height)
self.depth = input('depth: ')
Elem.CheckInput(self.depth)
Elem.Elem_count += 1
if Elem.Elem_count > 2:
exit
def Display_Elem(self):
print('\n')
if Elem.Elem_count == 0:
print('Element ')
print('width: ' + self.width)
print('Height: ' + self.height)
print('Depth: ' + self.depth)
else:
print('Element ')
print('width: ' + self.width)
print('Height: ' + self.height)
print('Depth: ' + self.depth)
def main():
First_Elem = Elem()
Second_Elem = Elem()
First_Elem.Add_Elem()
Second_Elem.Add_Elem()
print ("Elements added:")
First_Elem.Display_Elem()
Second_Elem.Display_Elem()
if __name__ == "__main__":
main()
Your issue is here:
def CheckInput(input):
For a normal class method, you'll have a definition like this:
def my_method(self, some_parameter):
The self here refers to the class. While you can pass in some other class, the behavior quickly becomes undefined. Your TypeError points to this, though: CheckInput() must be called with Elem instance as first argument (got int instance instead).
This means an int was passed - which is likely the parameter you meant. All you need is this:
def CheckInput(self, candidate_input):
try:
val = int(candidate_input)
except ValueError:
try:
val = float(candidate_input)
except ValueError:
print(f"Could not convert '{candidate_input}' to a number!")
return val
Note the change of input to candidate_input to avoid builtin name collision, and the use of the candidate input in the output string to allow the user to understand what was happening with bad input.
Also, it's likely that you want to return the value that you have - though it's not great design to have a function that returns one of two types of numbers.
To me the easiest fix would be to remove the checkinput method from your elem class ; it is useless for it to be in the class because it doesn't use the attributes of the class.
Also, you shouldn't name a variable "input" as it is the name of a builtin in both Python 2 and Python 3.
def CheckInput(data):
try:
# Convert it into integer
val = int(data)
except ValueError:
try:
# Convert it into float
val = float(data)
except ValueError:
print("You have entered a string, please use numbers!")
class Elem():
Elem_count = 0
def Add_Elem(self):
if Elem.Elem_count == 0:
print('Enter first Elem info:')
self.width = input('width: ')
CheckInput(self.width)
self.height = input('Height: ')
CheckInput(self.height)
self.depth = input('depth: ')
CheckInput(self.depth)
else:
print('Enter second Elem info:')
self.width = input('width: ')
CheckInput(self.width)
self.height = input('Height: ')
CheckInput(self.height)
self.depth = input('depth: ')
CheckInput(self.depth)
Elem.Elem_count += 1
if Elem.Elem_count > 2:
exit
def Display_Elem(self):
print('\n')
if Elem.Elem_count == 0:
print('Element ')
print('width: ' + self.width)
print('Height: ' + self.height)
print('Depth: ' + self.depth)
else:
print('Element ')
print('width: ' + self.width)
print('Height: ' + self.height)
print('Depth: ' + self.depth)

Chess in Python: list indices must be integers, not str

I wrote early version of chess in python. I have a problem with this:
File "C:/Users/Goldsmitd/PycharmProjects/CHESS/chess_ver0.04.py", line 39, in move
self.board[destination_x][destination_y] = 1
TypeError: list indices must be integers, not str
my code:
class Chess_Board:
def __init__(self):
self.board = self.create_board()
def create_board(self):
board_x=[]
for x in range(8):
board_y =[]
for y in range(8):
if (x==7 and y==4):
board_y.append('K')
elif (x== 7 and y == 3):
board_y.append('Q')
else:
board_y.append('.')
board_x.append(board_y)
return board_x
class WHITE_KING(Chess_Board):
def __init__(self):
Chess_Board.__init__(self)
self.symbol = 'K'
self.position_x = 7
self.position_y = 4
def move (self):
print ('give x and y cordinates fo white king')
destination_x = input()
destination_y = input()
self.board[destination_x][destination_y] = 'K'
I don't know what does not work
The value recieved from input() has a 'string' type (even if it looks like number), so you should convert it to integer.
self.board[int(destination_x)][int(destination_y)] = 'K'
The code above will fail if you enter something else than digits, so it is better to add an additional check before:
def move (self):
destination_x = None
destination_y = None
while not (destination_x and destination_y):
print ('give x and y cordinates fo white king')
try:
destination_x = int(input())
destination_y = int(input())
except ValueError as e:
pass
self.board[destination_x][destination_y] = 'K'

code optimization for memory game

I made this memory card matching game for class and feel like I wrote more code than I had to. Is there any way to optimize this? The assignment was just to get a working program but I feel like I need to learn a little bit of optimization.
import random
class Card(object):
""" A card object with value but not suit"""
def __init__(self, value):
"""Creates a card with the given value and suit."""
self.value = value
self.face = 0
def showFace(self):
'''flips the card over'''
self.face = 1
def __str__(self):
"""Returns the string representation of a card."""
return str(self.value)
class Deck(object):
""" A deck containing cards."""
def __init__(self, rows, columns):
"""Creates a full deck of cards."""
self._cards = []
self._rows = rows
self._columns = columns
for value in range(1,(int((self._rows*self._columns)/2))+1):
c = Card(value)
self._cards.append(c)
self._cards.append(c)
def shuffle(self):
"""Shuffles the cards."""
random.shuffle(self._cards)
def deal(self):
"""Removes and returns the top card or None
if the deck is empty."""
if len(self) == 0:
return None
else:
return self._cards.pop(0)
def __len__(self):
"""Returns the number of cards left in the deck."""
return len(self._cards)
def __str__(self):
"""Returns the string representation of a deck."""
self.result = ''
for c in self._cards:
self.result = self.result + str(c) + '\n'
return self.result
class Game(Deck,Card):
'''Runs the memory game'''
def __init__(self, rows, columns):
'''gets rows and columns for the game'''
self._rows = rows
self._columns = columns
def play(self):
'''starts the game'''
self._deck = Deck(self._rows, self._columns)
self._deck.shuffle()
Game.populateBoard(self)
matches = 0
#While the game is not finished
while True:
while True: #The First Card
try:
coor1 = input("Enter coordinates for first card ")
coor1 = coor1.split(' ') # Removes spaces
coor1 = [x for x in coor1 if x != ' '] # puts in list
coor1 = [int(x)-1 for x in coor1 if x == x] # converts
except IndexError:
print('***Invalid coordinates! Try again.***')
except ValueError:
print('***Invalid coordinates! Try again.***')
else:
try: #Check if coordinates are valid
if 0 > coor1[0] or coor1[0] > self._rows\
or 0 > coor1[1] or coor1[1] > self._columns:
print('***Invalid coordinates! Try again.***')
else:
guess1 = self._gameboard[coor1[0]][coor1[1]]
break
except IndexError:
print('***Invalid coordinates! Try again.***')
while True: # The Second Card
try:
coor2 = input("Enter coordinates for second card ")
coor2 = coor2.split(' ') # Removes Spaces
coor2 = [x for x in coor2 if x != ' '] # puts in list
coor2 = [int(x)-1 for x in coor2 if x == x]# converts
except IndexError:
print('***Invalid coordinates! Try again.***')
except ValueError:
print('***Invalid coordinates! Try again.***')
else:
try: #Check if coordinates are valid
if 0 > coor2[0] or coor2[0] > self._rows\
or 0 > coor2[1] or coor2[1] > self._columns:
print('***Invalid coordinates! Try again.***')
else:
guess2 = self._gameboard[coor2[0]][coor2[1]]
break
except IndexError:
print('***Invalid coordinates! Try again.***')
if guess1 == guess2\
and coor2[0]-coor1[0] == 0\
and coor2[1]-coor1[1] == 0:#User enters same input for 1 and 2
print("***That's the same card! Try again.***")
elif guess1 == guess2:
guess1.showFace()
Game.showBoard(self)
matches += 1
if matches == ((self._rows * self._columns)/2):
break
else:
Game.showBoard(self)
print('Not an identical pair. Found',guess1,'at ('+
str(coor1[0]+1)+','+ str(coor1[1]+1)+') and', guess2,
'at ('+str(coor2[0]+1)+','+str(coor2[1]+1)+')')
def populateBoard(self):
'''populates the game board'''
self._gameboard = []
for row in range(self._rows):
self._gameboard.append([0] * self._columns)
for row in range(len(self._gameboard)):
for column in range(len(self._gameboard[row])):
self._gameboard[row][column] = self._deck.deal()
Game.showBoard(self)
def showBoard(self):
'''shows the board'''
for row in self._gameboard:
for card in row:
if card.face == 0:
print('*', end =" ")
else:
print(card, end= " ")
print()
def main():
while True:
# Force user to enter valid value for number of rows
while True:
rows = input("Enter number of rows ")
if rows.isdigit() and ( 1 <= int(rows) <= 9):
rows = int(rows)
break
else:
print (" ***Number of rows must be between 1 and 9! Try again.***")
# Adding *** and indenting error message makes it easier for the user to see
# Force user to enter valid value for number of columns
while True:
columns = input("Enter number of columns ")
if columns.isdigit() and ( 1 <= int(columns) <= 9):
columns = int(columns)
break
else:
print (" ***Number of columns must be between 1 and 9! Try again.***")
if rows * columns % 2 == 0:
break
else:
print (" ***The value of rows X columns must be even. Try again.***")
game = Game(rows, columns)
game.play()
if __name__ == "__main__":
main()
Here is a couple of places the code can be simplified
def populateBoard(self):
'''populates the game board'''
self._gameboard = [self._deck.deal() for row in self._rows
for column in self._columns]
self.showBoard()
and
def showBoard(self):
'''shows the board'''
for row in self._gameboard:
print(*(card if card.face else '*' for card in row))
coor1[0] is computed many times over. Consider assigning the result to a local variable and then using this local variable.

What does string index out of range mean?

I am attempting to make a reversi game using python. this is the code for a blank board
#reversi
import random
import sys
board = range(9)
def char_range(start, end, step=1):
for char in range(ord(start), ord(end), step):
yield char
def drawBoard(board):
###this prints out the board
HLINE = ' +-+-+-+-+-+-+-+-+'
VLINE = ' | | | | | | | | |'
print(' a b c d e f g h')
print(HLINE)
for y in range(8):
print(y+1, end = '|.|')
for x in char_range('a','h'):
print('| %s' %(board[x][y]), end='.')
print('|')
print(HLINE)
def resetBoard(board):
#blanks out the board
for x in char_range('a', 'h'):
for y in range(8):
board[x][y] = '.'
#starters
board[c][3] = 'X'
board[c][4] = 'O'
board[d][3] = 'O'
board[d][4] = 'X'
def getNewBoard():
#new board
board = []
for i in range(9):
board.append([' '] * 9)
return board
getNewBoard()
drawBoard(board)
resetBoard(board)
for some reason when i execute it i get this message:
File "C:\Users\Larry\Desktop\test.py", line 18, in drawBoard
print('| %s' % (board[x][y]), end='.')
IndexError: string index out of range
what does this mean. do i need to change
char_range()
or the
print('| %s' % (board[x][y]), end='.')
As wim commented, a dict is often a perfectly fine way to implement a board like this
def getNewBoard():
#new board
board = {}
for x in range(8): # or x in 'abcdefgh': if you prefer
for y in range(8):
board[x, y] = ' '
return board
And don't forget to assign the board to board
board = getNewBoard()

Categories