Yu-Gi-Oh cards in Python 3 The Next CEO of Stack OverflowGenerating playing cardsASCII-fication of playing cardsFunction for shuffling cardsDynamic class instancing (with conditional parameters and methods) based on a dictionaryMy first finished Python program: a deck of cardsDeck of cards designMaking a deck of cards in PythonPoker Hand classifer part 3: Deck Object and 7 Card HandSimple Deck of Cards Python ProgramDeal three Poker hands of five cards each in Python
Would a grinding machine be a simple and workable propulsion system for an interplanetary spacecraft?
Read/write a pipe-delimited file line by line with some simple text manipulation
How can the PCs determine if an item is a phylactery?
Is it possible to create a QR code using text?
pgfplots: How to draw a tangent graph below two others?
Compensation for working overtime on Saturdays
How should I connect my cat5 cable to connectors having an orange-green line?
Is it reasonable to ask other researchers to send me their previous grant applications?
Find the majority element, which appears more than half the time
Early programmable calculators with RS-232
Is a linearly independent set whose span is dense a Schauder basis?
Why did the Drakh emissary look so blurred in S04:E11 "Lines of Communication"?
Is there a rule of thumb for determining the amount one should accept for a settlement offer?
Mathematica command that allows it to read my intentions
What is the difference between 'contrib' and 'non-free' packages repositories?
How to unfasten electrical subpanel attached with ramset
How can I prove that a state of equilibrium is unstable?
How to pronounce fünf in 45
What steps are necessary to read a Modern SSD in Medieval Europe?
Another proof that dividing by 0 does not exist -- is it right?
Shortening a title without changing its meaning
How can I replace x-axis labels with pre-determined symbols?
How to compactly explain secondary and tertiary characters without resorting to stereotypes?
Is it a bad idea to plug the other end of ESD strap to wall ground?
Yu-Gi-Oh cards in Python 3
The Next CEO of Stack OverflowGenerating playing cardsASCII-fication of playing cardsFunction for shuffling cardsDynamic class instancing (with conditional parameters and methods) based on a dictionaryMy first finished Python program: a deck of cardsDeck of cards designMaking a deck of cards in PythonPoker Hand classifer part 3: Deck Object and 7 Card HandSimple Deck of Cards Python ProgramDeal three Poker hands of five cards each in Python
$begingroup$
I made a project in Python 3.7.1 that includes classes to create Yu-Gi-Oh cards. This isn't the entire game; it is just the cards itself. I will create the entire game later. I want feedback on how to improve my code.
class Deck(object):
def __init__(self, main_deck):
self.main_deck = main_deck
def add_normal_cards(self, card_to_add, all_cards):
"""
Add monsters, spells and traps to the deck.
"""
if len(self.main_deck) > 60:
return "You have to many cards in your deck (60)."
else:
card_counter = 0
# Check to see how many copies of a card there are in your deck. Maximum 3 of the same card. Limited cards
# will be added eventually.
for card in self.main_deck:
if card == card_to_add:
card_counter += 1
if card_counter == 3:
return "You have to many copies of that card in your deck (3)."
else:
if card_to_add not in all_cards:
return "That card hasn't been added to the game yet (" + card_to_add + ")."
else:
self.main_deck.append(card_to_add)
def add_extra_cards(self, card_to_add, all_cards):
"""
Add monsters, spells and traps to the deck.
"""
if len(self.main_deck) > 15:
return "You have to many cards in your extra deck (15)."
else:
card_counter = 0
# Check to see how many copies of a card there are in your deck. Maximum 3 of the same card. Limited cards
# will be added eventually.
for card in self.main_deck:
if card == card_to_add:
card_counter += 1
if card_counter == 3:
return "You have to many copies of that card in your deck (3)."
else:
if card_to_add not in all_cards:
return "That card hasn't been added to the game yet (" + card_to_add + ")."
else:
self.main_deck.append(card_to_add)
class Monster(object):
def __init__(self, name, effects, attributes, monster_type, atk, _def, description):
self.name = name
self.effects = effects
self.attributes = attributes
self.type = monster_type
self.atk = atk
self._def = _def
self.description = description
def effect(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
class Spell(object):
def __init__(self, name, effects):
self.name = name
self.effects = effects
def activate(self):
"""
Activate the effect of this spell.
"""
for effect in self.effects:
eval(effect)
class Trap(object):
def __init__(self, name, effects):
self.name = name
self.effects = effects
def activate(self):
"""
Activate the effect of this spell.
"""
for effect in self.effects:
eval(effect)
class LinkMonster(object):
def __init__(self, name, effects, attributes, monster_type, atk, link_rating, description, recipe, links):
self.name = name
self.effects = effects
self.attributes = attributes
self.type = monster_type
self.atk = atk
self.link_rating = link_rating
self.description = description
self.recipe = recipe
self.links = links
def activate(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
class SynchroMonster(object):
def __init__(self, name, effects, attributes, monster_type, atk, _def, description, recipe):
self.name = name
self.effects = effects
self.attributes = attributes
self.type = monster_type
self.atk = atk
self._def = _def
self.description = description
self.recipe = recipe
def activate(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
class XyzMonster(object):
def __init__(self, name, effects, attributes, monster_type, atk, _def, description, recipe):
self.name = name
self.effects = effects
self.attributes = attributes
self.type = monster_type
self.atk = atk
self._def = _def
self.description = description
self.recipe = recipe
self.materials = recipe
def activate(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
class FusionMonster(object):
def __init__(self, name, effects, attributes, monster_type, atk, _def, description, recipe):
self.name = name
self.effects = effects
self.attributes = attributes
self.type = monster_type
self.atk = atk
self._def = _def
self.description = description
self.recipe = recipe
def activate(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
class PendulumMonster(object):
def __init__(self, name, effects, pendulum_effects, pendulum_scale, attributes, monster_type, atk, _def,
description, recipe):
self.name = name
self.effects = effects
self.pendulum_effects = pendulum_effects
self.pendulum_scale = pendulum_scale
self.attributes = attributes
self.type = monster_type
self.atk = atk
self._def = _def
self.description = description
self.recipe = recipe
self.materials = recipe
def activate(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
def pendulum_activate(self):
"""
Activate the effect of this monster while in Spell/Trap Zone.
"""
for effect in self.pendulum_effects:
eval(effect)
python python-3.x playing-cards
$endgroup$
add a comment |
$begingroup$
I made a project in Python 3.7.1 that includes classes to create Yu-Gi-Oh cards. This isn't the entire game; it is just the cards itself. I will create the entire game later. I want feedback on how to improve my code.
class Deck(object):
def __init__(self, main_deck):
self.main_deck = main_deck
def add_normal_cards(self, card_to_add, all_cards):
"""
Add monsters, spells and traps to the deck.
"""
if len(self.main_deck) > 60:
return "You have to many cards in your deck (60)."
else:
card_counter = 0
# Check to see how many copies of a card there are in your deck. Maximum 3 of the same card. Limited cards
# will be added eventually.
for card in self.main_deck:
if card == card_to_add:
card_counter += 1
if card_counter == 3:
return "You have to many copies of that card in your deck (3)."
else:
if card_to_add not in all_cards:
return "That card hasn't been added to the game yet (" + card_to_add + ")."
else:
self.main_deck.append(card_to_add)
def add_extra_cards(self, card_to_add, all_cards):
"""
Add monsters, spells and traps to the deck.
"""
if len(self.main_deck) > 15:
return "You have to many cards in your extra deck (15)."
else:
card_counter = 0
# Check to see how many copies of a card there are in your deck. Maximum 3 of the same card. Limited cards
# will be added eventually.
for card in self.main_deck:
if card == card_to_add:
card_counter += 1
if card_counter == 3:
return "You have to many copies of that card in your deck (3)."
else:
if card_to_add not in all_cards:
return "That card hasn't been added to the game yet (" + card_to_add + ")."
else:
self.main_deck.append(card_to_add)
class Monster(object):
def __init__(self, name, effects, attributes, monster_type, atk, _def, description):
self.name = name
self.effects = effects
self.attributes = attributes
self.type = monster_type
self.atk = atk
self._def = _def
self.description = description
def effect(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
class Spell(object):
def __init__(self, name, effects):
self.name = name
self.effects = effects
def activate(self):
"""
Activate the effect of this spell.
"""
for effect in self.effects:
eval(effect)
class Trap(object):
def __init__(self, name, effects):
self.name = name
self.effects = effects
def activate(self):
"""
Activate the effect of this spell.
"""
for effect in self.effects:
eval(effect)
class LinkMonster(object):
def __init__(self, name, effects, attributes, monster_type, atk, link_rating, description, recipe, links):
self.name = name
self.effects = effects
self.attributes = attributes
self.type = monster_type
self.atk = atk
self.link_rating = link_rating
self.description = description
self.recipe = recipe
self.links = links
def activate(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
class SynchroMonster(object):
def __init__(self, name, effects, attributes, monster_type, atk, _def, description, recipe):
self.name = name
self.effects = effects
self.attributes = attributes
self.type = monster_type
self.atk = atk
self._def = _def
self.description = description
self.recipe = recipe
def activate(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
class XyzMonster(object):
def __init__(self, name, effects, attributes, monster_type, atk, _def, description, recipe):
self.name = name
self.effects = effects
self.attributes = attributes
self.type = monster_type
self.atk = atk
self._def = _def
self.description = description
self.recipe = recipe
self.materials = recipe
def activate(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
class FusionMonster(object):
def __init__(self, name, effects, attributes, monster_type, atk, _def, description, recipe):
self.name = name
self.effects = effects
self.attributes = attributes
self.type = monster_type
self.atk = atk
self._def = _def
self.description = description
self.recipe = recipe
def activate(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
class PendulumMonster(object):
def __init__(self, name, effects, pendulum_effects, pendulum_scale, attributes, monster_type, atk, _def,
description, recipe):
self.name = name
self.effects = effects
self.pendulum_effects = pendulum_effects
self.pendulum_scale = pendulum_scale
self.attributes = attributes
self.type = monster_type
self.atk = atk
self._def = _def
self.description = description
self.recipe = recipe
self.materials = recipe
def activate(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
def pendulum_activate(self):
"""
Activate the effect of this monster while in Spell/Trap Zone.
"""
for effect in self.pendulum_effects:
eval(effect)
python python-3.x playing-cards
$endgroup$
$begingroup$
What you really need are some unit tests. I see some pretty noticable bugs in theDeck
class, that a simple test would highlight
$endgroup$
– flakes
yesterday
add a comment |
$begingroup$
I made a project in Python 3.7.1 that includes classes to create Yu-Gi-Oh cards. This isn't the entire game; it is just the cards itself. I will create the entire game later. I want feedback on how to improve my code.
class Deck(object):
def __init__(self, main_deck):
self.main_deck = main_deck
def add_normal_cards(self, card_to_add, all_cards):
"""
Add monsters, spells and traps to the deck.
"""
if len(self.main_deck) > 60:
return "You have to many cards in your deck (60)."
else:
card_counter = 0
# Check to see how many copies of a card there are in your deck. Maximum 3 of the same card. Limited cards
# will be added eventually.
for card in self.main_deck:
if card == card_to_add:
card_counter += 1
if card_counter == 3:
return "You have to many copies of that card in your deck (3)."
else:
if card_to_add not in all_cards:
return "That card hasn't been added to the game yet (" + card_to_add + ")."
else:
self.main_deck.append(card_to_add)
def add_extra_cards(self, card_to_add, all_cards):
"""
Add monsters, spells and traps to the deck.
"""
if len(self.main_deck) > 15:
return "You have to many cards in your extra deck (15)."
else:
card_counter = 0
# Check to see how many copies of a card there are in your deck. Maximum 3 of the same card. Limited cards
# will be added eventually.
for card in self.main_deck:
if card == card_to_add:
card_counter += 1
if card_counter == 3:
return "You have to many copies of that card in your deck (3)."
else:
if card_to_add not in all_cards:
return "That card hasn't been added to the game yet (" + card_to_add + ")."
else:
self.main_deck.append(card_to_add)
class Monster(object):
def __init__(self, name, effects, attributes, monster_type, atk, _def, description):
self.name = name
self.effects = effects
self.attributes = attributes
self.type = monster_type
self.atk = atk
self._def = _def
self.description = description
def effect(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
class Spell(object):
def __init__(self, name, effects):
self.name = name
self.effects = effects
def activate(self):
"""
Activate the effect of this spell.
"""
for effect in self.effects:
eval(effect)
class Trap(object):
def __init__(self, name, effects):
self.name = name
self.effects = effects
def activate(self):
"""
Activate the effect of this spell.
"""
for effect in self.effects:
eval(effect)
class LinkMonster(object):
def __init__(self, name, effects, attributes, monster_type, atk, link_rating, description, recipe, links):
self.name = name
self.effects = effects
self.attributes = attributes
self.type = monster_type
self.atk = atk
self.link_rating = link_rating
self.description = description
self.recipe = recipe
self.links = links
def activate(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
class SynchroMonster(object):
def __init__(self, name, effects, attributes, monster_type, atk, _def, description, recipe):
self.name = name
self.effects = effects
self.attributes = attributes
self.type = monster_type
self.atk = atk
self._def = _def
self.description = description
self.recipe = recipe
def activate(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
class XyzMonster(object):
def __init__(self, name, effects, attributes, monster_type, atk, _def, description, recipe):
self.name = name
self.effects = effects
self.attributes = attributes
self.type = monster_type
self.atk = atk
self._def = _def
self.description = description
self.recipe = recipe
self.materials = recipe
def activate(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
class FusionMonster(object):
def __init__(self, name, effects, attributes, monster_type, atk, _def, description, recipe):
self.name = name
self.effects = effects
self.attributes = attributes
self.type = monster_type
self.atk = atk
self._def = _def
self.description = description
self.recipe = recipe
def activate(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
class PendulumMonster(object):
def __init__(self, name, effects, pendulum_effects, pendulum_scale, attributes, monster_type, atk, _def,
description, recipe):
self.name = name
self.effects = effects
self.pendulum_effects = pendulum_effects
self.pendulum_scale = pendulum_scale
self.attributes = attributes
self.type = monster_type
self.atk = atk
self._def = _def
self.description = description
self.recipe = recipe
self.materials = recipe
def activate(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
def pendulum_activate(self):
"""
Activate the effect of this monster while in Spell/Trap Zone.
"""
for effect in self.pendulum_effects:
eval(effect)
python python-3.x playing-cards
$endgroup$
I made a project in Python 3.7.1 that includes classes to create Yu-Gi-Oh cards. This isn't the entire game; it is just the cards itself. I will create the entire game later. I want feedback on how to improve my code.
class Deck(object):
def __init__(self, main_deck):
self.main_deck = main_deck
def add_normal_cards(self, card_to_add, all_cards):
"""
Add monsters, spells and traps to the deck.
"""
if len(self.main_deck) > 60:
return "You have to many cards in your deck (60)."
else:
card_counter = 0
# Check to see how many copies of a card there are in your deck. Maximum 3 of the same card. Limited cards
# will be added eventually.
for card in self.main_deck:
if card == card_to_add:
card_counter += 1
if card_counter == 3:
return "You have to many copies of that card in your deck (3)."
else:
if card_to_add not in all_cards:
return "That card hasn't been added to the game yet (" + card_to_add + ")."
else:
self.main_deck.append(card_to_add)
def add_extra_cards(self, card_to_add, all_cards):
"""
Add monsters, spells and traps to the deck.
"""
if len(self.main_deck) > 15:
return "You have to many cards in your extra deck (15)."
else:
card_counter = 0
# Check to see how many copies of a card there are in your deck. Maximum 3 of the same card. Limited cards
# will be added eventually.
for card in self.main_deck:
if card == card_to_add:
card_counter += 1
if card_counter == 3:
return "You have to many copies of that card in your deck (3)."
else:
if card_to_add not in all_cards:
return "That card hasn't been added to the game yet (" + card_to_add + ")."
else:
self.main_deck.append(card_to_add)
class Monster(object):
def __init__(self, name, effects, attributes, monster_type, atk, _def, description):
self.name = name
self.effects = effects
self.attributes = attributes
self.type = monster_type
self.atk = atk
self._def = _def
self.description = description
def effect(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
class Spell(object):
def __init__(self, name, effects):
self.name = name
self.effects = effects
def activate(self):
"""
Activate the effect of this spell.
"""
for effect in self.effects:
eval(effect)
class Trap(object):
def __init__(self, name, effects):
self.name = name
self.effects = effects
def activate(self):
"""
Activate the effect of this spell.
"""
for effect in self.effects:
eval(effect)
class LinkMonster(object):
def __init__(self, name, effects, attributes, monster_type, atk, link_rating, description, recipe, links):
self.name = name
self.effects = effects
self.attributes = attributes
self.type = monster_type
self.atk = atk
self.link_rating = link_rating
self.description = description
self.recipe = recipe
self.links = links
def activate(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
class SynchroMonster(object):
def __init__(self, name, effects, attributes, monster_type, atk, _def, description, recipe):
self.name = name
self.effects = effects
self.attributes = attributes
self.type = monster_type
self.atk = atk
self._def = _def
self.description = description
self.recipe = recipe
def activate(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
class XyzMonster(object):
def __init__(self, name, effects, attributes, monster_type, atk, _def, description, recipe):
self.name = name
self.effects = effects
self.attributes = attributes
self.type = monster_type
self.atk = atk
self._def = _def
self.description = description
self.recipe = recipe
self.materials = recipe
def activate(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
class FusionMonster(object):
def __init__(self, name, effects, attributes, monster_type, atk, _def, description, recipe):
self.name = name
self.effects = effects
self.attributes = attributes
self.type = monster_type
self.atk = atk
self._def = _def
self.description = description
self.recipe = recipe
def activate(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
class PendulumMonster(object):
def __init__(self, name, effects, pendulum_effects, pendulum_scale, attributes, monster_type, atk, _def,
description, recipe):
self.name = name
self.effects = effects
self.pendulum_effects = pendulum_effects
self.pendulum_scale = pendulum_scale
self.attributes = attributes
self.type = monster_type
self.atk = atk
self._def = _def
self.description = description
self.recipe = recipe
self.materials = recipe
def activate(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)
def pendulum_activate(self):
"""
Activate the effect of this monster while in Spell/Trap Zone.
"""
for effect in self.pendulum_effects:
eval(effect)
python python-3.x playing-cards
python python-3.x playing-cards
edited yesterday
Jamal♦
30.6k11121227
30.6k11121227
asked 2 days ago
Jerry CuiJerry Cui
115111
115111
$begingroup$
What you really need are some unit tests. I see some pretty noticable bugs in theDeck
class, that a simple test would highlight
$endgroup$
– flakes
yesterday
add a comment |
$begingroup$
What you really need are some unit tests. I see some pretty noticable bugs in theDeck
class, that a simple test would highlight
$endgroup$
– flakes
yesterday
$begingroup$
What you really need are some unit tests. I see some pretty noticable bugs in the
Deck
class, that a simple test would highlight$endgroup$
– flakes
yesterday
$begingroup$
What you really need are some unit tests. I see some pretty noticable bugs in the
Deck
class, that a simple test would highlight$endgroup$
– flakes
yesterday
add a comment |
5 Answers
5
active
oldest
votes
$begingroup$
Trim redundant else
...here:
if len(self.main_deck) > 60:
return "You have to many cards in your deck (60)."
else:
The else
isn't needed because you've already returned. This pattern happens in a few places.
Lose some loops
This:
card_counter = 0
for card in self.main_deck:
if card == card_to_add:
card_counter += 1
can be
card_counter = sum(1 for card in self.main_deck if card == card_to_add)
If this happens often, you may want to do some preprocessing in a different method to make this easier. As in the comments, it shouldn't replace the sequential-format deck, but it could supplement it:
from collections import Counter
card_counts = Counter(main_deck)
# ...
card_counter = card_counts[card_to_add]
Don't eval
Just don't. There's never a good reason. Make effects
an iterable of functions, and simply call them.
$endgroup$
3
$begingroup$
I would argue that the first point is a manner of style. I personally prefer writing it like you have suggested, but sometimes I do it the other way to be explicit.
$endgroup$
– Quelklef
yesterday
$begingroup$
@IlmariKaronen That's a good point. There's nothing saying you can't do both.
$endgroup$
– Reinderien
yesterday
$begingroup$
@IlmariKaronen edited.
$endgroup$
– Reinderien
yesterday
$begingroup$
@IlmariKaronen I'd forgotten aboutCounter
; good idea.
$endgroup$
– Reinderien
yesterday
1
$begingroup$
Nice edits. I would still suggestself.main_deck.count(card_to_add)
oversum(1 for card in self.main_deck if card == card_to_add)
, though.
$endgroup$
– Ilmari Karonen
yesterday
|
show 1 more comment
$begingroup$
dataclasses.dataclass
would single handedly remove the majority of your code.from dataclasses import dataclass
from typing import List
@dataclass
class Monster(object):
name: str
effects: List[str]
attributes: str
type: str
atk: int
def_: int
description: str
def effect(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)Your classes are setup for inheritance.
class FusionMonster(Monster):
passI'd use composition over inheritance. This as equip monster cards can go into multiple types. It should be noted that things like Relinquished can make any monster an equipable.
Your current
effect
method doesn't care about any of the timing rules. This wiki page seems pretty complete on explaining the edge cases. I remember having this happen a couple times, IIRC it was because of my opponent playing an Iron Chain deck.IIRC to do this you'd want to make a 'chain' class that is a stack, you then put all of the effects onto the stack. Once you have built the stack you then run backwards through the chain to to resolve the effects. (I.e. build with
Stack.append
and resolve withStack.pop
.)A rudimentary example would be a D.D. deck vs a Frog deck.
Say I use my Dupe frog to attack and kill itself to one of your monsters, to send it to the graveyard to start up my combo. If dimensional fissure was a quick spell. After I declare my attack, you could use DF, if that's the end of the chain then DFs effect would activate. Then Dupe frog wouldn't be sent to the graveyard and its timing would be missed.
Yugioh has a lot of infinite loops, and so you should design the chain class to take these into affect too.
I think taking these factors into account at the start are very important as it'll force you to implement your code in the correct manner.
$endgroup$
add a comment |
$begingroup$
Since you're using python 3.7, I would take advantage of f-strings.
For example, this:
return "That card hasn't been added to the game yet (" + card_to_add + ")."
Becomes:
return f"That card hasn't been added to the game yet (card_to_add)."
As others have said, avoid hardcoding magic numbers like 60, 3 etc.
Give these numbers meaningful names so that it is immediately obvious
what the numbers represent.
Also, unless I'm missing something critical, those monster classes are begging to use inheritance.
New contributor
$endgroup$
add a comment |
$begingroup$
- I know you're trying to abbreviate "defense," but you could consider writing the whole thing out instead of making inconsistent naming with the preceding underscore. As such, you could write out "attack" as well to keep it more consistent.
- Perhaps all those monster classes should be part of a common base class inheritance. There are a lot of repeated
self
statements and similar functions (especiallyactivate()
), making the code harder to follow and maintain. The
60
,15
, and3
are "magic numbers" (numbers without some kind of given context), and from where they are, they could be harder to maintain.Although Python doesn't have actual constants like other languages, you can still do something similar above the functions:
MAX_DECK_CARDS = 60
MAX_EXTRA_CARDS = 15
MAX_EXTRA_CARDS = 3
There's a grammatical error here:
"You have to many copies of that card in your deck (3)."
It should be "too" instead of "to."
$endgroup$
3
$begingroup$
ATK and DEF are probably considered special terminology in Yu-Gi-Oh.
$endgroup$
– jingyu9575
yesterday
$begingroup$
@jingyu9575: I was already aware of that (maybe I didn't word it as such).
$endgroup$
– Jamal♦
yesterday
add a comment |
$begingroup$
In your class Deck
the methods add_normal_card
and add_extra_cards
share a lot of duplicated code which only differs in the maximum number of allowed cards and the error message displayed if this number is exceeded.
You could pull out the else
path in an own method.
Also I was a bit confused about the attribute main_deck
which is passed in __init__
:
- since the class itself is already named
Deck
one could assume thatmain_deck
is also an instance of some kind of customDeck
class, while it is just alist
. This could be clarified by picking another name (likelist_of_cards
), adding a docstring to__init__
or using type hints. add_extra_cards
checks the size ofmain_deck
but returns the error message "You have to many cards in your extra deck (15)." I would assume that an extra deck and main deck are separate instances. Is this a bug?
Last but not least the error handling of add_normal_cards
and add_extra_cards
can be improved. Right now they simply return None
if all went well (which is OK), but if some of your conditions like maximum desk size are not met you simply return a str
.
Think about the caller of your methods and how he or she should handle those errors.
With your current implementation, they would need to check if the returned object is not None
and then compare string values to determine what happened and react to it.
This is error prone because if you decide to change the phrasing of your return values the caller's code will break.
Instead, you should raise a meaningful exception. Since you are dealing with three potential problems, you should define two custom exception classes, like DeckSizeExceeded
and CardCountExceeded
.
The last possible error (card_to_add not in all_cards
) could simply lead to an IndexError, so there is no need for a custom exception class here.
New contributor
$endgroup$
add a comment |
StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216560%2fyu-gi-oh-cards-in-python-3%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
Trim redundant else
...here:
if len(self.main_deck) > 60:
return "You have to many cards in your deck (60)."
else:
The else
isn't needed because you've already returned. This pattern happens in a few places.
Lose some loops
This:
card_counter = 0
for card in self.main_deck:
if card == card_to_add:
card_counter += 1
can be
card_counter = sum(1 for card in self.main_deck if card == card_to_add)
If this happens often, you may want to do some preprocessing in a different method to make this easier. As in the comments, it shouldn't replace the sequential-format deck, but it could supplement it:
from collections import Counter
card_counts = Counter(main_deck)
# ...
card_counter = card_counts[card_to_add]
Don't eval
Just don't. There's never a good reason. Make effects
an iterable of functions, and simply call them.
$endgroup$
3
$begingroup$
I would argue that the first point is a manner of style. I personally prefer writing it like you have suggested, but sometimes I do it the other way to be explicit.
$endgroup$
– Quelklef
yesterday
$begingroup$
@IlmariKaronen That's a good point. There's nothing saying you can't do both.
$endgroup$
– Reinderien
yesterday
$begingroup$
@IlmariKaronen edited.
$endgroup$
– Reinderien
yesterday
$begingroup$
@IlmariKaronen I'd forgotten aboutCounter
; good idea.
$endgroup$
– Reinderien
yesterday
1
$begingroup$
Nice edits. I would still suggestself.main_deck.count(card_to_add)
oversum(1 for card in self.main_deck if card == card_to_add)
, though.
$endgroup$
– Ilmari Karonen
yesterday
|
show 1 more comment
$begingroup$
Trim redundant else
...here:
if len(self.main_deck) > 60:
return "You have to many cards in your deck (60)."
else:
The else
isn't needed because you've already returned. This pattern happens in a few places.
Lose some loops
This:
card_counter = 0
for card in self.main_deck:
if card == card_to_add:
card_counter += 1
can be
card_counter = sum(1 for card in self.main_deck if card == card_to_add)
If this happens often, you may want to do some preprocessing in a different method to make this easier. As in the comments, it shouldn't replace the sequential-format deck, but it could supplement it:
from collections import Counter
card_counts = Counter(main_deck)
# ...
card_counter = card_counts[card_to_add]
Don't eval
Just don't. There's never a good reason. Make effects
an iterable of functions, and simply call them.
$endgroup$
3
$begingroup$
I would argue that the first point is a manner of style. I personally prefer writing it like you have suggested, but sometimes I do it the other way to be explicit.
$endgroup$
– Quelklef
yesterday
$begingroup$
@IlmariKaronen That's a good point. There's nothing saying you can't do both.
$endgroup$
– Reinderien
yesterday
$begingroup$
@IlmariKaronen edited.
$endgroup$
– Reinderien
yesterday
$begingroup$
@IlmariKaronen I'd forgotten aboutCounter
; good idea.
$endgroup$
– Reinderien
yesterday
1
$begingroup$
Nice edits. I would still suggestself.main_deck.count(card_to_add)
oversum(1 for card in self.main_deck if card == card_to_add)
, though.
$endgroup$
– Ilmari Karonen
yesterday
|
show 1 more comment
$begingroup$
Trim redundant else
...here:
if len(self.main_deck) > 60:
return "You have to many cards in your deck (60)."
else:
The else
isn't needed because you've already returned. This pattern happens in a few places.
Lose some loops
This:
card_counter = 0
for card in self.main_deck:
if card == card_to_add:
card_counter += 1
can be
card_counter = sum(1 for card in self.main_deck if card == card_to_add)
If this happens often, you may want to do some preprocessing in a different method to make this easier. As in the comments, it shouldn't replace the sequential-format deck, but it could supplement it:
from collections import Counter
card_counts = Counter(main_deck)
# ...
card_counter = card_counts[card_to_add]
Don't eval
Just don't. There's never a good reason. Make effects
an iterable of functions, and simply call them.
$endgroup$
Trim redundant else
...here:
if len(self.main_deck) > 60:
return "You have to many cards in your deck (60)."
else:
The else
isn't needed because you've already returned. This pattern happens in a few places.
Lose some loops
This:
card_counter = 0
for card in self.main_deck:
if card == card_to_add:
card_counter += 1
can be
card_counter = sum(1 for card in self.main_deck if card == card_to_add)
If this happens often, you may want to do some preprocessing in a different method to make this easier. As in the comments, it shouldn't replace the sequential-format deck, but it could supplement it:
from collections import Counter
card_counts = Counter(main_deck)
# ...
card_counter = card_counts[card_to_add]
Don't eval
Just don't. There's never a good reason. Make effects
an iterable of functions, and simply call them.
edited yesterday
answered yesterday
ReinderienReinderien
5,250926
5,250926
3
$begingroup$
I would argue that the first point is a manner of style. I personally prefer writing it like you have suggested, but sometimes I do it the other way to be explicit.
$endgroup$
– Quelklef
yesterday
$begingroup$
@IlmariKaronen That's a good point. There's nothing saying you can't do both.
$endgroup$
– Reinderien
yesterday
$begingroup$
@IlmariKaronen edited.
$endgroup$
– Reinderien
yesterday
$begingroup$
@IlmariKaronen I'd forgotten aboutCounter
; good idea.
$endgroup$
– Reinderien
yesterday
1
$begingroup$
Nice edits. I would still suggestself.main_deck.count(card_to_add)
oversum(1 for card in self.main_deck if card == card_to_add)
, though.
$endgroup$
– Ilmari Karonen
yesterday
|
show 1 more comment
3
$begingroup$
I would argue that the first point is a manner of style. I personally prefer writing it like you have suggested, but sometimes I do it the other way to be explicit.
$endgroup$
– Quelklef
yesterday
$begingroup$
@IlmariKaronen That's a good point. There's nothing saying you can't do both.
$endgroup$
– Reinderien
yesterday
$begingroup$
@IlmariKaronen edited.
$endgroup$
– Reinderien
yesterday
$begingroup$
@IlmariKaronen I'd forgotten aboutCounter
; good idea.
$endgroup$
– Reinderien
yesterday
1
$begingroup$
Nice edits. I would still suggestself.main_deck.count(card_to_add)
oversum(1 for card in self.main_deck if card == card_to_add)
, though.
$endgroup$
– Ilmari Karonen
yesterday
3
3
$begingroup$
I would argue that the first point is a manner of style. I personally prefer writing it like you have suggested, but sometimes I do it the other way to be explicit.
$endgroup$
– Quelklef
yesterday
$begingroup$
I would argue that the first point is a manner of style. I personally prefer writing it like you have suggested, but sometimes I do it the other way to be explicit.
$endgroup$
– Quelklef
yesterday
$begingroup$
@IlmariKaronen That's a good point. There's nothing saying you can't do both.
$endgroup$
– Reinderien
yesterday
$begingroup$
@IlmariKaronen That's a good point. There's nothing saying you can't do both.
$endgroup$
– Reinderien
yesterday
$begingroup$
@IlmariKaronen edited.
$endgroup$
– Reinderien
yesterday
$begingroup$
@IlmariKaronen edited.
$endgroup$
– Reinderien
yesterday
$begingroup$
@IlmariKaronen I'd forgotten about
Counter
; good idea.$endgroup$
– Reinderien
yesterday
$begingroup$
@IlmariKaronen I'd forgotten about
Counter
; good idea.$endgroup$
– Reinderien
yesterday
1
1
$begingroup$
Nice edits. I would still suggest
self.main_deck.count(card_to_add)
over sum(1 for card in self.main_deck if card == card_to_add)
, though.$endgroup$
– Ilmari Karonen
yesterday
$begingroup$
Nice edits. I would still suggest
self.main_deck.count(card_to_add)
over sum(1 for card in self.main_deck if card == card_to_add)
, though.$endgroup$
– Ilmari Karonen
yesterday
|
show 1 more comment
$begingroup$
dataclasses.dataclass
would single handedly remove the majority of your code.from dataclasses import dataclass
from typing import List
@dataclass
class Monster(object):
name: str
effects: List[str]
attributes: str
type: str
atk: int
def_: int
description: str
def effect(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)Your classes are setup for inheritance.
class FusionMonster(Monster):
passI'd use composition over inheritance. This as equip monster cards can go into multiple types. It should be noted that things like Relinquished can make any monster an equipable.
Your current
effect
method doesn't care about any of the timing rules. This wiki page seems pretty complete on explaining the edge cases. I remember having this happen a couple times, IIRC it was because of my opponent playing an Iron Chain deck.IIRC to do this you'd want to make a 'chain' class that is a stack, you then put all of the effects onto the stack. Once you have built the stack you then run backwards through the chain to to resolve the effects. (I.e. build with
Stack.append
and resolve withStack.pop
.)A rudimentary example would be a D.D. deck vs a Frog deck.
Say I use my Dupe frog to attack and kill itself to one of your monsters, to send it to the graveyard to start up my combo. If dimensional fissure was a quick spell. After I declare my attack, you could use DF, if that's the end of the chain then DFs effect would activate. Then Dupe frog wouldn't be sent to the graveyard and its timing would be missed.
Yugioh has a lot of infinite loops, and so you should design the chain class to take these into affect too.
I think taking these factors into account at the start are very important as it'll force you to implement your code in the correct manner.
$endgroup$
add a comment |
$begingroup$
dataclasses.dataclass
would single handedly remove the majority of your code.from dataclasses import dataclass
from typing import List
@dataclass
class Monster(object):
name: str
effects: List[str]
attributes: str
type: str
atk: int
def_: int
description: str
def effect(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)Your classes are setup for inheritance.
class FusionMonster(Monster):
passI'd use composition over inheritance. This as equip monster cards can go into multiple types. It should be noted that things like Relinquished can make any monster an equipable.
Your current
effect
method doesn't care about any of the timing rules. This wiki page seems pretty complete on explaining the edge cases. I remember having this happen a couple times, IIRC it was because of my opponent playing an Iron Chain deck.IIRC to do this you'd want to make a 'chain' class that is a stack, you then put all of the effects onto the stack. Once you have built the stack you then run backwards through the chain to to resolve the effects. (I.e. build with
Stack.append
and resolve withStack.pop
.)A rudimentary example would be a D.D. deck vs a Frog deck.
Say I use my Dupe frog to attack and kill itself to one of your monsters, to send it to the graveyard to start up my combo. If dimensional fissure was a quick spell. After I declare my attack, you could use DF, if that's the end of the chain then DFs effect would activate. Then Dupe frog wouldn't be sent to the graveyard and its timing would be missed.
Yugioh has a lot of infinite loops, and so you should design the chain class to take these into affect too.
I think taking these factors into account at the start are very important as it'll force you to implement your code in the correct manner.
$endgroup$
add a comment |
$begingroup$
dataclasses.dataclass
would single handedly remove the majority of your code.from dataclasses import dataclass
from typing import List
@dataclass
class Monster(object):
name: str
effects: List[str]
attributes: str
type: str
atk: int
def_: int
description: str
def effect(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)Your classes are setup for inheritance.
class FusionMonster(Monster):
passI'd use composition over inheritance. This as equip monster cards can go into multiple types. It should be noted that things like Relinquished can make any monster an equipable.
Your current
effect
method doesn't care about any of the timing rules. This wiki page seems pretty complete on explaining the edge cases. I remember having this happen a couple times, IIRC it was because of my opponent playing an Iron Chain deck.IIRC to do this you'd want to make a 'chain' class that is a stack, you then put all of the effects onto the stack. Once you have built the stack you then run backwards through the chain to to resolve the effects. (I.e. build with
Stack.append
and resolve withStack.pop
.)A rudimentary example would be a D.D. deck vs a Frog deck.
Say I use my Dupe frog to attack and kill itself to one of your monsters, to send it to the graveyard to start up my combo. If dimensional fissure was a quick spell. After I declare my attack, you could use DF, if that's the end of the chain then DFs effect would activate. Then Dupe frog wouldn't be sent to the graveyard and its timing would be missed.
Yugioh has a lot of infinite loops, and so you should design the chain class to take these into affect too.
I think taking these factors into account at the start are very important as it'll force you to implement your code in the correct manner.
$endgroup$
dataclasses.dataclass
would single handedly remove the majority of your code.from dataclasses import dataclass
from typing import List
@dataclass
class Monster(object):
name: str
effects: List[str]
attributes: str
type: str
atk: int
def_: int
description: str
def effect(self):
"""
Activate the effect of this monster.
"""
for effect in self.effects:
eval(effect)Your classes are setup for inheritance.
class FusionMonster(Monster):
passI'd use composition over inheritance. This as equip monster cards can go into multiple types. It should be noted that things like Relinquished can make any monster an equipable.
Your current
effect
method doesn't care about any of the timing rules. This wiki page seems pretty complete on explaining the edge cases. I remember having this happen a couple times, IIRC it was because of my opponent playing an Iron Chain deck.IIRC to do this you'd want to make a 'chain' class that is a stack, you then put all of the effects onto the stack. Once you have built the stack you then run backwards through the chain to to resolve the effects. (I.e. build with
Stack.append
and resolve withStack.pop
.)A rudimentary example would be a D.D. deck vs a Frog deck.
Say I use my Dupe frog to attack and kill itself to one of your monsters, to send it to the graveyard to start up my combo. If dimensional fissure was a quick spell. After I declare my attack, you could use DF, if that's the end of the chain then DFs effect would activate. Then Dupe frog wouldn't be sent to the graveyard and its timing would be missed.
Yugioh has a lot of infinite loops, and so you should design the chain class to take these into affect too.
I think taking these factors into account at the start are very important as it'll force you to implement your code in the correct manner.
answered yesterday
PeilonrayzPeilonrayz
26.5k338111
26.5k338111
add a comment |
add a comment |
$begingroup$
Since you're using python 3.7, I would take advantage of f-strings.
For example, this:
return "That card hasn't been added to the game yet (" + card_to_add + ")."
Becomes:
return f"That card hasn't been added to the game yet (card_to_add)."
As others have said, avoid hardcoding magic numbers like 60, 3 etc.
Give these numbers meaningful names so that it is immediately obvious
what the numbers represent.
Also, unless I'm missing something critical, those monster classes are begging to use inheritance.
New contributor
$endgroup$
add a comment |
$begingroup$
Since you're using python 3.7, I would take advantage of f-strings.
For example, this:
return "That card hasn't been added to the game yet (" + card_to_add + ")."
Becomes:
return f"That card hasn't been added to the game yet (card_to_add)."
As others have said, avoid hardcoding magic numbers like 60, 3 etc.
Give these numbers meaningful names so that it is immediately obvious
what the numbers represent.
Also, unless I'm missing something critical, those monster classes are begging to use inheritance.
New contributor
$endgroup$
add a comment |
$begingroup$
Since you're using python 3.7, I would take advantage of f-strings.
For example, this:
return "That card hasn't been added to the game yet (" + card_to_add + ")."
Becomes:
return f"That card hasn't been added to the game yet (card_to_add)."
As others have said, avoid hardcoding magic numbers like 60, 3 etc.
Give these numbers meaningful names so that it is immediately obvious
what the numbers represent.
Also, unless I'm missing something critical, those monster classes are begging to use inheritance.
New contributor
$endgroup$
Since you're using python 3.7, I would take advantage of f-strings.
For example, this:
return "That card hasn't been added to the game yet (" + card_to_add + ")."
Becomes:
return f"That card hasn't been added to the game yet (card_to_add)."
As others have said, avoid hardcoding magic numbers like 60, 3 etc.
Give these numbers meaningful names so that it is immediately obvious
what the numbers represent.
Also, unless I'm missing something critical, those monster classes are begging to use inheritance.
New contributor
New contributor
answered yesterday
user10987432user10987432
812
812
New contributor
New contributor
add a comment |
add a comment |
$begingroup$
- I know you're trying to abbreviate "defense," but you could consider writing the whole thing out instead of making inconsistent naming with the preceding underscore. As such, you could write out "attack" as well to keep it more consistent.
- Perhaps all those monster classes should be part of a common base class inheritance. There are a lot of repeated
self
statements and similar functions (especiallyactivate()
), making the code harder to follow and maintain. The
60
,15
, and3
are "magic numbers" (numbers without some kind of given context), and from where they are, they could be harder to maintain.Although Python doesn't have actual constants like other languages, you can still do something similar above the functions:
MAX_DECK_CARDS = 60
MAX_EXTRA_CARDS = 15
MAX_EXTRA_CARDS = 3
There's a grammatical error here:
"You have to many copies of that card in your deck (3)."
It should be "too" instead of "to."
$endgroup$
3
$begingroup$
ATK and DEF are probably considered special terminology in Yu-Gi-Oh.
$endgroup$
– jingyu9575
yesterday
$begingroup$
@jingyu9575: I was already aware of that (maybe I didn't word it as such).
$endgroup$
– Jamal♦
yesterday
add a comment |
$begingroup$
- I know you're trying to abbreviate "defense," but you could consider writing the whole thing out instead of making inconsistent naming with the preceding underscore. As such, you could write out "attack" as well to keep it more consistent.
- Perhaps all those monster classes should be part of a common base class inheritance. There are a lot of repeated
self
statements and similar functions (especiallyactivate()
), making the code harder to follow and maintain. The
60
,15
, and3
are "magic numbers" (numbers without some kind of given context), and from where they are, they could be harder to maintain.Although Python doesn't have actual constants like other languages, you can still do something similar above the functions:
MAX_DECK_CARDS = 60
MAX_EXTRA_CARDS = 15
MAX_EXTRA_CARDS = 3
There's a grammatical error here:
"You have to many copies of that card in your deck (3)."
It should be "too" instead of "to."
$endgroup$
3
$begingroup$
ATK and DEF are probably considered special terminology in Yu-Gi-Oh.
$endgroup$
– jingyu9575
yesterday
$begingroup$
@jingyu9575: I was already aware of that (maybe I didn't word it as such).
$endgroup$
– Jamal♦
yesterday
add a comment |
$begingroup$
- I know you're trying to abbreviate "defense," but you could consider writing the whole thing out instead of making inconsistent naming with the preceding underscore. As such, you could write out "attack" as well to keep it more consistent.
- Perhaps all those monster classes should be part of a common base class inheritance. There are a lot of repeated
self
statements and similar functions (especiallyactivate()
), making the code harder to follow and maintain. The
60
,15
, and3
are "magic numbers" (numbers without some kind of given context), and from where they are, they could be harder to maintain.Although Python doesn't have actual constants like other languages, you can still do something similar above the functions:
MAX_DECK_CARDS = 60
MAX_EXTRA_CARDS = 15
MAX_EXTRA_CARDS = 3
There's a grammatical error here:
"You have to many copies of that card in your deck (3)."
It should be "too" instead of "to."
$endgroup$
- I know you're trying to abbreviate "defense," but you could consider writing the whole thing out instead of making inconsistent naming with the preceding underscore. As such, you could write out "attack" as well to keep it more consistent.
- Perhaps all those monster classes should be part of a common base class inheritance. There are a lot of repeated
self
statements and similar functions (especiallyactivate()
), making the code harder to follow and maintain. The
60
,15
, and3
are "magic numbers" (numbers without some kind of given context), and from where they are, they could be harder to maintain.Although Python doesn't have actual constants like other languages, you can still do something similar above the functions:
MAX_DECK_CARDS = 60
MAX_EXTRA_CARDS = 15
MAX_EXTRA_CARDS = 3
There's a grammatical error here:
"You have to many copies of that card in your deck (3)."
It should be "too" instead of "to."
edited 14 hours ago
Mast
7,58763788
7,58763788
answered yesterday
Jamal♦Jamal
30.6k11121227
30.6k11121227
3
$begingroup$
ATK and DEF are probably considered special terminology in Yu-Gi-Oh.
$endgroup$
– jingyu9575
yesterday
$begingroup$
@jingyu9575: I was already aware of that (maybe I didn't word it as such).
$endgroup$
– Jamal♦
yesterday
add a comment |
3
$begingroup$
ATK and DEF are probably considered special terminology in Yu-Gi-Oh.
$endgroup$
– jingyu9575
yesterday
$begingroup$
@jingyu9575: I was already aware of that (maybe I didn't word it as such).
$endgroup$
– Jamal♦
yesterday
3
3
$begingroup$
ATK and DEF are probably considered special terminology in Yu-Gi-Oh.
$endgroup$
– jingyu9575
yesterday
$begingroup$
ATK and DEF are probably considered special terminology in Yu-Gi-Oh.
$endgroup$
– jingyu9575
yesterday
$begingroup$
@jingyu9575: I was already aware of that (maybe I didn't word it as such).
$endgroup$
– Jamal♦
yesterday
$begingroup$
@jingyu9575: I was already aware of that (maybe I didn't word it as such).
$endgroup$
– Jamal♦
yesterday
add a comment |
$begingroup$
In your class Deck
the methods add_normal_card
and add_extra_cards
share a lot of duplicated code which only differs in the maximum number of allowed cards and the error message displayed if this number is exceeded.
You could pull out the else
path in an own method.
Also I was a bit confused about the attribute main_deck
which is passed in __init__
:
- since the class itself is already named
Deck
one could assume thatmain_deck
is also an instance of some kind of customDeck
class, while it is just alist
. This could be clarified by picking another name (likelist_of_cards
), adding a docstring to__init__
or using type hints. add_extra_cards
checks the size ofmain_deck
but returns the error message "You have to many cards in your extra deck (15)." I would assume that an extra deck and main deck are separate instances. Is this a bug?
Last but not least the error handling of add_normal_cards
and add_extra_cards
can be improved. Right now they simply return None
if all went well (which is OK), but if some of your conditions like maximum desk size are not met you simply return a str
.
Think about the caller of your methods and how he or she should handle those errors.
With your current implementation, they would need to check if the returned object is not None
and then compare string values to determine what happened and react to it.
This is error prone because if you decide to change the phrasing of your return values the caller's code will break.
Instead, you should raise a meaningful exception. Since you are dealing with three potential problems, you should define two custom exception classes, like DeckSizeExceeded
and CardCountExceeded
.
The last possible error (card_to_add not in all_cards
) could simply lead to an IndexError, so there is no need for a custom exception class here.
New contributor
$endgroup$
add a comment |
$begingroup$
In your class Deck
the methods add_normal_card
and add_extra_cards
share a lot of duplicated code which only differs in the maximum number of allowed cards and the error message displayed if this number is exceeded.
You could pull out the else
path in an own method.
Also I was a bit confused about the attribute main_deck
which is passed in __init__
:
- since the class itself is already named
Deck
one could assume thatmain_deck
is also an instance of some kind of customDeck
class, while it is just alist
. This could be clarified by picking another name (likelist_of_cards
), adding a docstring to__init__
or using type hints. add_extra_cards
checks the size ofmain_deck
but returns the error message "You have to many cards in your extra deck (15)." I would assume that an extra deck and main deck are separate instances. Is this a bug?
Last but not least the error handling of add_normal_cards
and add_extra_cards
can be improved. Right now they simply return None
if all went well (which is OK), but if some of your conditions like maximum desk size are not met you simply return a str
.
Think about the caller of your methods and how he or she should handle those errors.
With your current implementation, they would need to check if the returned object is not None
and then compare string values to determine what happened and react to it.
This is error prone because if you decide to change the phrasing of your return values the caller's code will break.
Instead, you should raise a meaningful exception. Since you are dealing with three potential problems, you should define two custom exception classes, like DeckSizeExceeded
and CardCountExceeded
.
The last possible error (card_to_add not in all_cards
) could simply lead to an IndexError, so there is no need for a custom exception class here.
New contributor
$endgroup$
add a comment |
$begingroup$
In your class Deck
the methods add_normal_card
and add_extra_cards
share a lot of duplicated code which only differs in the maximum number of allowed cards and the error message displayed if this number is exceeded.
You could pull out the else
path in an own method.
Also I was a bit confused about the attribute main_deck
which is passed in __init__
:
- since the class itself is already named
Deck
one could assume thatmain_deck
is also an instance of some kind of customDeck
class, while it is just alist
. This could be clarified by picking another name (likelist_of_cards
), adding a docstring to__init__
or using type hints. add_extra_cards
checks the size ofmain_deck
but returns the error message "You have to many cards in your extra deck (15)." I would assume that an extra deck and main deck are separate instances. Is this a bug?
Last but not least the error handling of add_normal_cards
and add_extra_cards
can be improved. Right now they simply return None
if all went well (which is OK), but if some of your conditions like maximum desk size are not met you simply return a str
.
Think about the caller of your methods and how he or she should handle those errors.
With your current implementation, they would need to check if the returned object is not None
and then compare string values to determine what happened and react to it.
This is error prone because if you decide to change the phrasing of your return values the caller's code will break.
Instead, you should raise a meaningful exception. Since you are dealing with three potential problems, you should define two custom exception classes, like DeckSizeExceeded
and CardCountExceeded
.
The last possible error (card_to_add not in all_cards
) could simply lead to an IndexError, so there is no need for a custom exception class here.
New contributor
$endgroup$
In your class Deck
the methods add_normal_card
and add_extra_cards
share a lot of duplicated code which only differs in the maximum number of allowed cards and the error message displayed if this number is exceeded.
You could pull out the else
path in an own method.
Also I was a bit confused about the attribute main_deck
which is passed in __init__
:
- since the class itself is already named
Deck
one could assume thatmain_deck
is also an instance of some kind of customDeck
class, while it is just alist
. This could be clarified by picking another name (likelist_of_cards
), adding a docstring to__init__
or using type hints. add_extra_cards
checks the size ofmain_deck
but returns the error message "You have to many cards in your extra deck (15)." I would assume that an extra deck and main deck are separate instances. Is this a bug?
Last but not least the error handling of add_normal_cards
and add_extra_cards
can be improved. Right now they simply return None
if all went well (which is OK), but if some of your conditions like maximum desk size are not met you simply return a str
.
Think about the caller of your methods and how he or she should handle those errors.
With your current implementation, they would need to check if the returned object is not None
and then compare string values to determine what happened and react to it.
This is error prone because if you decide to change the phrasing of your return values the caller's code will break.
Instead, you should raise a meaningful exception. Since you are dealing with three potential problems, you should define two custom exception classes, like DeckSizeExceeded
and CardCountExceeded
.
The last possible error (card_to_add not in all_cards
) could simply lead to an IndexError, so there is no need for a custom exception class here.
New contributor
New contributor
answered yesterday
dudenr33dudenr33
1943
1943
New contributor
New contributor
add a comment |
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216560%2fyu-gi-oh-cards-in-python-3%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
$begingroup$
What you really need are some unit tests. I see some pretty noticable bugs in the
Deck
class, that a simple test would highlight$endgroup$
– flakes
yesterday