Python memory matching game loop/logic issue - python

I am making a basic game of memory matching. The idea is that by user input a board can be created with cards. Those cards all have a match somewhere on the board. Basically the input is the dimensions of the board and then coordinates to identify possible matches. However everytime I enter input even if valid the code seems to defer to invalid input. However when I enter two identical coordinates the part of my code will execute for that case. I am not sure what is going on here.
import random
class Card():
"""Card object """
def __init__(self, val):
self.val = val
self.face = False
def isFaceUp(self):
"""check to see if the cards face up"""
return self.face
def getVal(self):
return self.val
def makeFaceUp(self):
self.face = True
def __str__(self):
return ", ".join(("Value: ", str(self.val), "Face: ", str(self.face)))
class Deck():
def __init__(self, pairs):
self._pairs = pairs
self._cards = []
for cards in range(self._pairs):
card1 = Card(cards + 1)
self._cards.append(card1)
card2 = Card(cards+1)
self._cards.append(card2)
def deal(self):
if len(self) ==0:
return None
else:
return self._cards.pop(0)
def shuffle(self):
random.shuffle(self._cards)
def __len__(self):
return len(self._cards)
class Game():
def __init__(self, rows, columns):
self._deck = Deck((rows*columns)//2)
self._rows = rows
self._columns = columns
self._board = []
for row in range(self._rows):
self._board.append([0] * self._columns)
self.populateBoard()
def populateBoard(self):
"""Puts all cards in the board random"""
self._deck.shuffle()
for columns in range(self._columns):
for rows in range(self._rows):
self._board[rows][columns] = self._deck.deal()
def revealBoard(self):
"""checks the values on the board making sure theres pairs"""
for rows in range(self._rows):
for columns in range(self._columns):
print(str(self._board[rows][columns].getVal()) + \
" ", end="")
print("")
def displayGame(self):
"""Displays the game in a 2d list"""
for rows in range(self._rows):
for columns in range(self._columns):
if self._board[rows][columns].isFaceUp() == False:
print("*", end = "")
else:
print(str(self._board[rows][columns].getVal() + \
" ", end = ""))
print("")
def play(self):
"""Allows the game to play setting the cards into a double list """
while not self.isGameOver():
self.displayGame()
c1 = input("Enter coordinates, (row, column) of card: ")
c2 = input("Enter the coordinates of match: ")
newC1 = list(map(int, c1.split()))
newCard1 = self._board[(newC1[0])-1][(newC1[1])-1] #Get value here???
newC2 = list(map(int, c2.split()))
newCard2 = self._board[(newC2[0])-1][(newC2[1])-1]
try:
if newCard1 != newCard2:
print("Not a pair", "Found: ",newCard1, "at", "(" + newC1, ", ", newC2, ")")
elif newC1 == newC2:
print("Identical Coordinate Entery")
elif newCard1.getVal() == newCard2.getVal():
self._board[newC1[0]-1][newC1[1]-1].makeFaceUp()
self._board[newC2[0]-1][newC2[1]-1].makeFaceUp()
print("pair found")
except:
print("invalid input")
print("Game Over")
self.displayGame
def isGameOver(self):
"""Test to determine if all the cards are facing up and revelied the game will be over"""
for rows in range(self._rows):
if not all(card.isFaceUp() for card in self._board[rows]):
return False
return True
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()
Any help is appreciated and if anyone would need to see other parts of my code simply ask I'd be happy to put them in there if it will help finding this error.
Edit: Went ahead and added the whole code for testing.

Okay, so from what I could deduce, the error is your very broad error handling in Game.play(). It checks for any error, but when you remove that statement, you could see that you were trying to add a list to a string. To fix that, add in:
newC1 = "(" + ", ".join (list (map (str, newC1))) + ")"
Do the same for newC2. This just changes the lists into strings that look like coordinates.

Related

Increase the first 15 digits of a 16 digit number by 1 within a range

Background
I am trying to ensure I am generating a unique credit card number. The credit card number needs to be 16 digits long with the last digit equal to the checksum which in this case is self.checksum = 1.
The first 6 digits of the credit card number must be 400000.
Since the last digit must be equal to the checksum or 1 in this case, I believe I need to implement a range in my code somehow to indicate when the maximum credit card number has been issued. In this case, the maximum credit card number is 40000009999999991. Anything after that would change the first 6 digits.
While the current solution "works" it does so by only adding 10 to the first possible credit card number initialized in the __init__ as self.credit_card_number = 4000000000000001.
Help needed
I am looking for help taking my existing code and implementing a range of some sort that can alert when the last credit card number in the range has been issued.
from random import randrange
class Accounts:
def __init__(self):
self.accounts_list = []
self.all_accounts = dict()
self.balance = 0
# Initial credit card number
self.credit_card_number = 4000000000000001
# Checksum is the last digit (16th) in the credit card number.
self.checksum = 1
# Pin number is generated in account_creation
self.pin = None
def main_menu(self):
while True:
main_menu_choice = input('1. Create an account\n'
'2. Log into account\n'
'0. Exit\n')
if main_menu_choice == '1':
self.account_creation()
def account_creation(self):
# Create credit card number ensuring it is unique by adding 1 to initialized value.
if len(self.accounts_list) == 0:
self.credit_card_number = self.credit_card_number
else:
self.credit_card_number = self.credit_card_number
self.credit_card_number = self.credit_card_number + 10
# Create pin number.
pin = int(format(randrange(0000, 9999), '04d'))
# Add credit card number to list used in the above if statement.
self.accounts_list.append(self.credit_card_number)
# Add the credit card number, pin, and balance to dictionary.
self.all_accounts[self.credit_card_number] = {'pin': pin, 'balance': self.balance}
# Print the output to make sure everything is OK.
print(self.accounts_list)
# Print the output to make sure everything is OK.
print(self.all_accounts)
print(f'\n'
f'Your card has been created\n'
f'Your card number:\n'
f'{self.credit_card_number}\n'
f'Your card PIN:\n'
f'{pin}'
f'\n')
Accounts().main_menu()
Can you update your init to generate credit cards:
def __init__(self):
# do you stuff
self.credit_card_first_6 = '400000'
self.checksum = '1'
# this will be used to create a unique credit card
self.count = 0
# middle numbers MUST be smaller than this
self.max_count = 1000000000
def account_creation(self):
#### do your stuff
# for this user they have a unique 9 digits in the middle
# this is then zero padded using zfill
unique_id = str(self.count).zfill(9)
# create the full credit card number
# note: store each bit as a str so we can concat then convert to int
credit_card_number = int(self.credit_card_first_6 + unique_id + checksum)
self.count += 1
# update your init values when your limit is reached
if self.count >= self.max_count:
self.count = 0
self.credit_card_first_6 = str(int(self.credit_card_first_6) + 1)
Since you marked Matt's answer as a valid I've added a quick refactor with some extra code that might be use full to you.
class Account:
balance = 0
__pin = None # this are
__number = None # private members
def __eq__(self, other):
return self.__number == other
def is_pin(self, pin):
return self.__pin == pin
def number(self):
return self.__number
# adding a 'is not none' makes
# it a 'write only once' variable,
# if a 'none' text is added as a input
# text is added not a None type
def set_pin(self, pin):
if self.__pin is None:
self.__pin = pin
return True
return False
def set_number(self, num):
if self.__number is None \
and len(str(num)) == 16:
self.__number = num
return True
return False
# eeextra simple checksum
def checksum(self):
ck_sum = 0
for i in str(self.__number):
ck_sum += int(i)
return int(str(ck_sum)[-1])
class Accounts:
base_num = 4000000000000000
def __init__(self):
self.accounts = []
self.num_offset = 0
#staticmethod
def dialog_choice():
choice = input(
'1. Create an account\n'
'2. Log into account\n'
'0. Exit \n \n'
)
return choice
def next_card_num(self):
self.num_offset += 1
return self.base_num + self.num_offset
def dialog_acount_creation(self):
card_pin = input('New pin ->')
card_num = self.next_card_num()
print('Card number ->', card_num)
return card_num, card_pin
#staticmethod
def dialog_login():
card_num = input('Card number ->')
card_pin = input('Card pin ->')
return int(card_num), card_pin
#staticmethod
def dialog_error(*args):
print('Error on acount', args[0])
def main_loop(self):
dia_map = {
'1': self.dialog_acount_creation,
'2': self.dialog_login,
}
cho_map = {
'1': self.account_creation,
'2': self.account_login,
}
err_map = {
'1': self.dialog_error,
'2': self.dialog_error,
}
while True:
o = self.dialog_choice()
if o == '0':
break
if o in cho_map:
q_dialog = dia_map[o]()
q_done = cho_map[o](*q_dialog)
if not q_done:
err_map[o](*q_dialog)
else:
print('Invalid option')
def account_login(self, num, pin):
for acc in self.accounts:
if acc == num and acc.is_pin(pin):
print('You are logged in !')
return True
return False
def account_creation(self, num, pin):
new_accaunt = Account()
new_accaunt.set_number(num)
new_accaunt.set_pin(pin)
self.accounts.append(new_accaunt)
return True
if __name__ == '__main__':
h_acc = Accounts()
h_acc.account_creation(4000000000000000, '1234')
h_acc.main_loop()

Tkinter: Win check in scalable tic tac toe not working

I'm making a scalable tic tac toe game in Tkinter (meaning the board size can be 2x2 up to whatever fits the screen). I'm using cget("image") to find what mark a button has. For some reason, the win check displays very random things. I've tried a lot of semi-random things to fix it, but had no success in fixing it. Here's the code:
from tkinter import *
class XOGame:
def main_game(self):
self.__game_window = Tk()
self.__grid_size = 3 # User inputted in a different part of the code
self.__game_window.title("Tic Tac Toe (" + str(self.__grid_size) + "x"
+ str(self.__grid_size) + ")")
# this is user inputted in a different part of the program.
self.__players = ["p1", "p2"]
self.__player1 = self.__players[0]
self.__player2 = self.__players[1]
self.build_board(self.__game_window)
self.__game_window.mainloop()
def build_board(self, window):
self.__size = self.__grid_size ** 2
self.__turn_nr = 1
self.__win = False
self.__empty_square = PhotoImage(master=window,
file="rsz_empty.gif")
self.__x = PhotoImage(master=window,
file="rsz_cross.gif")
self.__o = PhotoImage(master=window,
file="rsz_nought.gif")
self.__squares = [None] * self.__size
self.create_win_check_lists()
# Building the buttons and gridding them
for i in range(self.__size):
self.__squares[i] = (Button(window, image=self.__empty_square))
row = 0
column = 0
number = 1
for j in self.__squares:
j.grid(row=row, column=column)
j.config(command=lambda index=self.__squares.index(j):
self.change_mark(index))
column += 1
if number % 3 == 0:
row += 1
column = 0
number += 1
# This is the part where the picture changing happens.
def change_mark(self, i):
"""
Function changes mark of empty button to either X or O depending on the
player in turn. It also checks if the change in mark results in a win.
:param i: The button number, whose mark is being changed
:return: None
"""
if self.__turn_nr % 2 == 1:
self.__player_in_turn = self.__player1
else:
self.__player_in_turn = self.__player2
if self.__player_in_turn == self.__player1:
self.__mark = self.__x
else:
self.__mark = self.__o
self.__squares[i].configure(image=self.__mark, state=DISABLED)
self.__turn_nr += 1
self.check_win(i)
if self.__win is True:
print("this is thought to be a win")
else:
print("the game thinks this is not a win")
# Checking if the game tied.
if self.__turn_nr == self.__size + 1 and not self.__win:
print("the game thinks it tied.")
def check_win(self, i):
"""
Checks if mark placement leads to a win.
:param i: i is the button location.
:return: None
"""
# checks row
if self.__win == False:
for row in self.__rows:
if i + 1 in row:
self.__win = self.checksameimage(row)
if self.__win == True:
break
# checks column
if self.__win == False:
for column in self.__columns:
if i + 1 in column:
self.__win = self.checksameimage(column)
if self.__win == True:
break
# if i is in a diagonal, checks one/both diagonals
if self.__win == False:
for diag in self.__diagonals:
if i + 1 in diag:
self.__win = self.checksameimage(diag)
if self.__win == True:
break
return self.__win
# checking if all the images are same
# This is likely where the issue is. Either this part or checkEqual.
def checksameimage(self, lst):
images = []
for nr in lst:
try:
images.append(self.__squares[nr].cget("image"))
except IndexError:
pass
return self.checkEqual(images)
def checkEqual(self, lst):
"""
Function checks if all elements in a list are equal. Used for checking
if the dice throws are the same.
:param lst: The list the check is performed on
:return: True/False, True if all elements are equal.
"""
if all(x == lst[0] for x in lst):
return True
else:
return False
def create_win_check_lists(self):
"""
Creates lists whose elements are lists of the locations of each spot
of the game board that belongs to a row/column/diagonal
:return:
"""
self.__rows = [[] for _ in range(self.__grid_size)]
for i in range(self.__grid_size):
self.__rows[i].append(i + 1)
for k in range(1, self.__grid_size):
self.__rows[i].append(i + 1 + self.__grid_size * k)
self.__columns = [[] for _ in range(self.__grid_size)]
for i in range(self.__grid_size):
for j in range(1, self.__grid_size + 1):
self.__columns[i].append(i * self.__grid_size + j)
self.getDiagonals(self.__columns)
def getDiagonals(self, lst):
self.__diagonals = [[], []]
self.__diagonals[0] = [lst[i][i] for i in range(len(lst))]
self.__diagonals[1] = [lst[i][len(lst) - i - 1] for i in
range(len(lst))]
def start(self):
# Function starts the first window of the game.
self.main_game()
def main():
ui = XOGame()
ui.start()
main()
The images used in the code are 125x125. Here is a link that works for 24h: https://picresize.com/b5df006025f0d8
your problem is unquestionably with indices. We can see what index each square corresponds to by changing the image to be text corresponding to the index:
Try changing this loop in build_board:
for i in range(self.__size):
self.__squares[i] = (Button(window, image=self.__empty_square))
To instead show the index it corresponds to:
for i in range(self.__size):
self.__squares[i] = (Button(window, text=str(i)))
Then print out lst passed to checksameimage and you will see that the indices you are checking are all one higher than you intended.

Why am I getting a Traceback (most recent call last):

I cannot create an object of class Animal. If I do so it gives me an error saying "Unresolved reference Animal" when the #FILE I/0 code is commented out.
And if the it isn't then it gives me the error as shown in the image. Traceback most recent call: last error
Can someone help me out with this? I'm making this complete file so that I can cover the basic syntax of PYTHON.
import random
import sys
import os
import math
#SIMPLE THINGS AND MATHS
print("STARTING SIMPLE THINGS AND MATHS!!!")
print("Hello World") #This is a code for printing hello world
#Comment
"""
This
is a
multiline
comment
"""
name = "Derek"
y="2"
print (y)
print(name)
#Numbers Strings List Tuples Dictionaries
#+ - * / % ** //
name=15
print(name)
print("5 + 2 =",5+2)
print("5 - 2 =",5-2)
print("5 * 2 =",5*2)
print("5 / 2 =",5/2)
print("5 % 2 =",5%2)
print("5 ** 2 =",5**2)
print("5 // 2 =",5//2)
print("1 + 2 - 3 * 2 =", 1 + 2 - 3 * 2)
print("(1 + 2 - 3) * 2 =", (1 + 2 - 3) * 2)
quote = "\"Always remember you are unique\""
print("Single line quote: ",quote)
multi_line_quote = "\"""""Just
like everyone else""""\""
print("Multi Line quote: ",multi_line_quote)
print("%s %s %s" %('I like the quote', quote, multi_line_quote))
print("I dont like ",end="")
print("newlines")
print('\n'*5)
print("LISTS!!!")
#LISTS
grocery_list = ['Juice','Tomatoes','Potatoes',
'Bananas']
print('First item: ',grocery_list[0])
grocery_list[0] = "Green Juice"
print('First item: ',grocery_list[0])
print(grocery_list[1:3])
other_events=['Wash Car', 'Pick Up Kids','Cash Check']
to_do_list = [other_events, grocery_list] #list within a list
print(to_do_list[1][1]) #2nd item of second list
grocery_list.append('Onions')
print(to_do_list)
grocery_list.insert(1,"Pickle") #Inserting item on second index
print(to_do_list)
grocery_list.remove("Pickle") #Removing pickle from grocery list
print(to_do_list)
grocery_list.sort() #Sorting grocery list alphabetically
print(to_do_list)
grocery_list.reverse() #Sorting grocery list in reverse order albhabetically
print(to_do_list)
del grocery_list[4] #Delete item from grocery list which is on index 4
print(to_do_list)
to_do_list2 = other_events + grocery_list
print(len(to_do_list2))
print(max(to_do_list2)) #Whatever comes last alphabetically
print(min(to_do_list2)) #Whatever comes first alphabetically
to_do_list2.insert(1,"Bananas")
print(min(to_do_list2))
print("\n"*5)
#Tuples
print("TUPLES!!!")
pi_tuple=(3,1,4,1,5,9)
new_tuple=list(pi_tuple) #Converting tuple to list
new_list=tuple(new_tuple) #Converting list to tuple
print(len(new_list))
print(max(new_list))
print(min(new_list))
print("\n"*5)
#Dictionaries
print("DICTIONARIES!!!")
super_villains={'Fiddler':'Isaac Bowin',
'Captain Cold': 'Leonard Snart',
'Weather Wizard': 'Mark Mardon',
'Mirror Master': 'Sam Scudder',
'Pied Piper':'Thomas Peterson'}
print(super_villains['Captain Cold'])
print(len(super_villains))
del super_villains['Fiddler']
super_villains['Pied Piper']='Hartley Rathway'
print(len(super_villains))
print(super_villains.get("Pied Piper"))
print(super_villains.keys())
print(super_villains.values())
print("\n"*5)
#IF ElSE ELIF == != > >= < <=
print("IF ElSE ELIF (== != > >= < <=)")
age=21
if age>16:
print("You are old enough to drive")
else:
print("You are not old enough to drive")
if age>=21:
print("You are old enough to drive a tractor trailer")
elif age>=16:
print("You are old enoguh to drive a car")
else:
print("You are not old enough to drive")
#LOGICAL OPERATORS (AND OR NOT)
age=30
if ((age>=1) and (age<=18)):
print("You get a birthday")
elif (age==21)or(age>=65):
print("You get a birthday")
elif not(age==30):
print("You don't get a birthday")
else:
print("You get a birthday party yeah")
print("\n"*5)
#LOOPS
print("LOOPS!!!")
print('\n')
print("FOR LOOPS!!!")
for x in range(0,10):
print(x,' ',end="")
print('\n')
grocery_list=['Juice','Tomatoes','Potatoes','Bananas']
for y in grocery_list:
print(y)
for x in [2,4,6,8,10]:
print(x)
print('\n')
num_list=[[1,2,3],[10,20,30],[100,200,300]]
for x in range(0,3):
for y in range(0,3):
print(num_list[x][y])
print('\n'*2)
print("WHILE LOOPS!!!")
random_num= random.randrange(0,16) #Generates a random number between 0 to 99
while(random_num!=15):
print(random_num)
random_num=random.randrange(0,16)
print('\n')
i=0;
while(i<=20):
if(i==0):
i += 1
continue
elif(i%2==0):
print(i)
elif(i==9):
break
else:
i+=1 #i=i+1
continue
i+=1
print('\n')
print('Finding prime numbers')
#FINDING PRIME NUMBERS BETWEEN 0 AND 20
max_num = 20
primes = [2] # start with 2
test_num = 3 # which means testing starts with 3
while test_num < max_num:
i = 0
# It's only necessary to check with the primes smaller than the square
# root of the test_num
while primes[i] <= math.sqrt(test_num):
# using modulo to figure out if test_num is prime or not
if (test_num % primes[i]) == 0:
test_num += 1
break
else:
i += 1
else:
primes.append(test_num)
test_num += 1
print(primes)
print('\n'*5)
#FUNCTIONS
print("FUNCTIONS")
def sum(fNum,lNum):
sumNum = fNum+lNum
return sumNum
sum_of_two = sum(1,2)
print(sum_of_two)
print("The sum of 1 and 2 is: ",sum(1,2))
print('\n'*5)
#TAKE INPUT FROM USER
print("TAKE INPUT FROM USER!!!")
print("What is your name: ")
#name = sys.stdin.readline()
#print("Hello ",name)
print('\n'*5)
#STRINGS
print("STRINGS!!!")
long_string="i'll catch you if you fall - The Floor"
print(long_string[0:4])
print(long_string[-5:])
print(long_string[:-5])
print(long_string[:4] + " be there")
print("%c is my %s letter and my number %d number is %.5f" %
('X','favorite',1,.14))
print(long_string.capitalize()) #Capitalizes first letter of the string
print(long_string.find("Floor"))
print(long_string.isalpha())
print(long_string.isalnum())
print(len(long_string))
print(long_string.replace("Floor","Ground"))
print(long_string.strip()) #Strip white space
quote_list = long_string.split(" ")
print(quote_list)
print('\n'*5)
#FILE I/0
print("FILE I/0!!!")
test_file = open("test.txt","wb") #Opens the files in write mode
print(test_file.mode)
print(test_file.name)
test_file.write(bytes("Write me to the file\n", 'UTF-8')) #Writes to the file
test_file.close()
test_file = open("test.txt","r+")
text_in_file = test_file.read()
print(text_in_file)
os.remove("test.txt") #Deletes the file
print('\n'*5)
#OBJECTS
print("OBJECTS!!!")
class Animal:
__name = None #or __name = ""
__height = 0
__weight = 0
__sound = 0
def __init__(self,name,height,weight,sound):
self.__name = name
self.__height = height
self.__weight = weight
self.__sound = sound
def set_name(self, name):
self.__name = name
def set_height(self, height):
self.__height = height
def set_weight(self, weight):
self.__weight = weight
def set_sound(self, sound):
self.__sound = sound
def get_name(self):
return self.__name
def get_height(self):
return str(self.__height)
def get_weight(self):
return str(self.__weight)
def get_sound(self):
return self.__sound
def get_type(self):
print("Animal")
def toString(self):
return "{} is {} cm tall and {} kilograms and say {}".format(self.__name,
self.__height,
self.__weight,
self.__sound)
cat = Animal('Whiskers',33,10,'Meow')
print(cat.toString())
It is an indentation problem. You are creating the instance of the Aninal class with in the class. Unindent last two lines out side of class.

TicTacToe Python with board size selection

Desperately trying to create a code for a python TicTacToe game.
Im quite new to Python so am stuck with a feature that I want to add.
The idea is that the player can select whether he wants to play with 2, 3 players or against the computer.
He then selects whether he would like to be X or O (or Y for 3 players)
He then selects any boardsize up to 9x9.
So far so good, the two player, NbyN and X or O selection works and I have split the code into three seperate files (two classes) for ease.
I am lost with trying to figure out how to create the computer algorithm and to extend the game to 3 players.
Has anyone got any idea how I could do this?
Below is the code:
Player File:
class Player:
def __init__(self, player_name, shape):
self.player_name = player_name
self.shape = shape
def get_player_loc_input(self, rows, columns):
player_input = input('Enter in location for your move: ') # player input is with respect to field index location/values
converted_input = int(player_input)
if 1 <= converted_input <= (rows * columns): # bound checking
converted_input -= 1 # adjust from n+1 to n
transformed_value = (rows-(converted_input//columns)-1, converted_input%columns) # (row,col) tuple obj
return transformed_value
else:
raise ValueError('Input is not an index on the playing field. Try again\n')#
TicTac File:
class TicTac:
def __init__(self, rows, columns):
#self.playing_field = [ [7,8,9], [4,5,6], [1,2,3] ] #init the playing field to their respective nums on the numpad: 3x3
self.winner_found = False
self.is_full = False
self.possible_moves_left = columns * rows
self.rows = rows
def DefineBoard():
field = []
value = (rows * columns)
for row in range(rows):
field.append([])
for col in range(columns):
field[row].insert(0, value)
value = value - 1
return field
self.playing_field = DefineBoard()
#value = (rows * columns)
#def decrement(x): return (x-1)
#self.playing_field = [ [ decrement(value) for i in range(columns) ] for i in range(rows)]
def DrawBoard(self): #prints playing field based on size input
print('-------------')
for list in self.playing_field:
print('| ', end='')
for item in list:
print(str(item) + ' | ', end='')
print('\n-------------')
def Instructions(self):
print('\n-------------------------------------')
print('When entering in the location please enter the number of the index you want to replace with your shape.')
print('\nPrinting Initial Playing Field...')
self.DrawBoard()
print('\nLet the game begin!')
print('-------------------------------------')
def PlayerMove(self, index, shape):
row, col = index[0], index[1]
field_value = self.playing_field[row][col]
#if the value is of type int we can replace it
if isinstance(field_value, int):
self.playing_field[row][col] = shape #overwrite the value
self.possible_moves_left -= 1 #reduce the moves left
#check possible moves after its been updated
if self.possible_moves_left == 0:
self.is_full = True
raise EnvironmentError('All index posistions filled.\nGame Over. Nobody won.')
#else its the Player's shape (string)
else:
raise ValueError('Invalid Index. Position already filled. Try again.\n')
def ConsecutiveSymbols(self):
def check_list(passed_list):
#fast & quick check to tell if the "row" is incomplete
if isinstance(passed_list[0], str):
player_shape = passed_list[0] # set to first val
#compare the values to each other
for val in passed_list:
if isinstance(val, int) or player_shape != val:
return False #we found an inconsistency
return True #everything matched up
def Diagonal(orientation):
DiagonalList = []
counter = 0 if orientation is 'LtR' else self.rows-1
for row in self.playing_field:
DiagonalList.append(row[counter])
counter = counter+1 if orientation is 'LtR' else counter-1
return DiagonalList
# check rows for match
for row_list in self.playing_field:
if check_list(row_list):
return True
#check cols for match
transposed_playing_field = [list(a) for a in zip(*self.playing_field)] #convert our tuples from zip to a list format
for col_list in transposed_playing_field:
if check_list(col_list):
return True
#check diagonals for match
if check_list(Diagonal('LtR')): #LtR \ gets replaced each time we check
return True
if check_list(Diagonal('RtL')): # RtL / gets replaced each time we check
return True
return False #if we got here then no matches were found
Main File:
try:
from .TicTac import TicTac
from .Player import Player
except Exception:
from TicTac import TicTac
from Player import Player
winners=[]
def GameBegins():
Game=input("Would you like to play with 2, 3 players or against the CPU?").upper()
if Game=="2":
selection=input("Player 1: Would you like to play as X or O?").upper()
if selection == "X":
Players = {'Player_1': Player('Player_1', "X"), 'Player_2': Player('Player_2', "O")}
elif selection == "O":
Players = {'Player_1': Player('Player_1', "O"), 'Player_2': Player('Player_2', "X")}
else:
print("Please enter either X or O")
return False
if Game=="3":
selection=input("Player 1: Would you like to play as X, O or Y?").upper()
if selection == "X":
selection2=input("Player 2: Would you like to play as O or Y?").upper()
if selection2=="O":
Players = {'Player_1': Player('Player_1', "X"),"Player_2":Player("Player_2","O"),"Player_3":Player("Player_3","Y")}
elif selection2=="Y":
Players = {'Player_1': Player('Player_1', "X"),"Player_2":Player("Player_2","Y"),"Player_3":Player("Player_3","O")}
else:
print("Please enter either O or Y")
return False
elif selection == "O":
selection2=input("Player 2: Would you like to play as X or Y?").upper()
if selection2=="X":
Players = {'Player_1': Player('Player_1', "O"),"Player_2":Player("Player_2","X"),"Player_3":Player("Player_3","Y")}
elif selection2=="Y":
Players = {'Player_1': Player('Player_1', "O"),"Player_2":Player("Player_2","Y"),"Player_3":Player("Player_3","X")}
else:
print("Please enter either X or Y")
return False
elif selection=="Y":
selection2=input("Player 2: Would you like to play as X or O?").upper()
if selection2=="X":
Players = {'Player_1': Player('Player_1', "Y"),"Player_2":Player("Player_2","X"),"Player_3":Player("Player_3","O")}
elif selection2=="O":
Players = {'Player_1': Player('Player_1', "Y"),"Player_2":Player("Player_2","O"),"Player_3":Player("Player_3","X")}
else:
print("Please enter either X or O")
return False
if Game=="CPU":
CPU()
x=input("enter boardsize: ")
if x >="2":
rows, columns = int(x),int(x) #Players input becomes board size
else:
print("Please enter a boardsize of 3 or more")
GameBegins()
global game
game = TicTac(rows, columns)
game.Instructions()
player_id = 'Player_1' # index to swap between players, Player_1 starts
while (game.winner_found == False and game.is_full == False):
print('\nIt\'s ' + Players[player_id].player_name + ' Turn')
# loop until user inputs correct index value
while True:
try:
index = Players[player_id].get_player_loc_input(rows,columns)
shape = Players[player_id].shape
game.PlayerMove(index, shape)
except ValueError as msg:
print(msg)
continue
except EnvironmentError as msg:
print(msg)
break
game.winner_found = game.ConsecutiveSymbols() # check if a player has won
game.DrawBoard()
if game.winner_found:
print(Players[player_id].player_name + ' has won!') # print player who won
winners.append(str(Players[player_id].player_name))
player_id = 'Player_2' if player_id is 'Player_1' else 'Player_1' # switch between the 2 players
Replay() # Game has ended. Play Again?
def Replay():
PlayerDecision = input('\nDo you want to play again? (Y/N) ')
PlayerDecision = PlayerDecision.upper() #force to uppercase for consistency
if PlayerDecision == 'Y':
GameBegins()
elif PlayerDecision == 'N':
file=open("winners.txt","w")
for w in winners:
file.write(str(winners))
file.close()
exit(0)
else:
print('Incorrect input.')
Replay()
def main():
while True:
GameBegins()
if __name__ == '__main__':
main()
Would really appreciate some suggestions, thanks in advance!

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.

Categories