วิธีที่ดีในการสร้างคลาสสำหรับประเภทการ์ดเล่นที่ซับซ้อนกว่าที่พบในสำรับมาตรฐานหรือไม่


9

ฉันใหม่มากสำหรับการเขียนโปรแกรมเชิงวัตถุและพยายามเริ่มเรียนรู้ด้วย python โดยการสร้างเกมไพ่อย่างง่าย (ตามที่ดูเหมือนจะเป็นแบบดั้งเดิม!) ฉันได้ทำตัวอย่างต่อไปนี้ซึ่งใช้งานได้ดีและสอนฉันเกี่ยวกับการสร้างอินสแตนซ์ของPlayingCard()คลาสที่หลากหลายเพื่อสร้างอินสแตนซ์ของDeck()คลาส:

class PlayingCard(object):
    def __init__(self, suit, val):
        self.suit = suit
        self.value = val

    def print_card(self):
        print("{} of {}".format(self.value, self.suit))

class Deck(object):
    def __init__(self):
        self.playingcards = []
        self.build()

    def build(self):
        for s in ["Spades", "Clubs", "Diamonds", "Hearts"]:
            for v in range(1,14):
                self.playingcards.append(PlayingCard(s,v))

deck = Deck()



ฉันต้องการสร้างบางสิ่งบางอย่างในขณะนี้ด้วยการ์ดที่ซับซ้อนมากขึ้นไม่ใช่แค่สำรับมาตรฐาน 52 สำรับ (ซึ่งมีค่าที่เพิ่มขึ้นอย่างมาก) เด็คที่ฉันมีอยู่ในใจคือเกมไพ่ Monopoly:

ป้อนคำอธิบายรูปภาพที่นี่

การ์ดพื้นฐานมี 3 ประเภท - การ์ด ACTION, PROPERTY cards และ MONEY cards บัตรการดำเนินการกระทำที่แตกต่างกันบัตรทรัพย์สินที่อยู่ในชุดสีที่แตกต่างกันและบัตรเงินสามารถมีค่าที่แตกต่างกัน นอกจากนี้การ์ดคุณสมบัติสามารถเป็น "wildcards" และสามารถใช้เป็นส่วนหนึ่งของหนึ่งในสองชุด ในที่สุดบัตรทุกใบก็มีมูลค่าเงินเท่ากัน (ระบุไว้ที่มุมด้านบนของบัตรแต่ละใบ) ในบัตรการเช่าดำเนินการบัตรสามารถนำไปใช้กับคุณสมบัติสีที่ระบุไว้บนบัตร

คำถามของฉันเป็นเพียงวิธีการจัดการกับสถานการณ์เช่นนี้และจะเป็นวิธีที่ดีในการรวมการ์ดที่แตกต่างกันเหล่านี้ในโปรแกรมหลามแบบคลาส? ฉันควรจะเก็บไว้คนเดียวของฉันชั้นและมีเพียงปัจจัยการผลิตเป็นจำนวนมากเช่นPlayingCard() PlayingCard(type="PROPERTY", value="3M")หรือมันจะดีกว่าการสร้างคลาสที่แยกต่างหากเช่นActionPlayingCard(), PropertyPlayingCard()etc? หรือมีวิธีที่ดีกว่า อย่างที่ฉันบอกว่าฉันเป็นจุดเริ่มต้นของการเรียนรู้ของฉันที่นี่และวิธีการจัดระเบียบสถานการณ์ประเภทนี้ในแง่ของการออกแบบระดับที่สูงขึ้น

ขอบคุณมาก.


หากคุณพบว่าการ์ดประเภทต่าง ๆ แบ่งปันคุณสมบัติบางอย่างคุณอาจใช้การสืบทอดหรือแม้กระทั่งคลาสนามธรรม คุณสามารถอ่านและใช้รูปแบบโรงงานเพื่อให้คุณผ่านประเภทของการ์ดและใช้คลาสที่เหมาะสม
Tomerikoo

@Tomerikoo ขอบคุณที่ชี้ให้เห็นว่า - ฉันได้อ่านเล็ก ๆ น้อย ๆ เกี่ยวกับรูปแบบโรงงานที่คุณพูดถึง ตามที่ฉันเข้าใจแล้วสิ่งนี้มีประโยชน์มากที่สุดเมื่อคุณไม่ทราบล่วงหน้าว่าจะต้องสร้างคลาสของออบเจ็กต์ใด อย่างไรก็ตามเนื่องจากในกรณีนี้ฉันรู้ว่าสำรับทั้งหมดควรมีลักษณะอย่างไร (มีการ์ดแต่ละประเภทกี่ประเภทสิ่งที่แต่ละคนทำ ฯลฯ ) มีรูปแบบของโรงงานที่นี่หรือไม่
teeeeee

คำตอบ:


3

เมื่อคุณกำลังเข้าใกล้ปัญหากับOOPคุณมักต้องการจำลองพฤติกรรมและคุณสมบัติด้วยวิธีที่สามารถนำกลับมาใช้ใหม่ได้เช่นคุณควรคิดถึง abstractions และจัดลำดับชั้นของคลาสของคุณตามนั้น

ฉันจะเขียนสิ่งต่อไปนี้:

class Card:
    def __init__(self, money_value=0):
        self.money_value = money_value

class ActionCard(Card):
    def __init__(self, action, money_value=0):
        super().__init__(money_value=money_value)

        self.action = action

class RentActionCard(ActionCard):
    def __init__(self, action, color, money_value=0):
        super().__init__(action, money_value=money_value)

        self.color = color

    def apply(self, property_card):
        if property_card.color != self.color:
            # Don't apply
        # Apply

class PropertyCard(Card):
    def __init__(self, color, money_value=0):
        super().__init__(money_value=money_value)

        self.color = color

class WildcardPropertyCard(PropertyCard):
    def __init__(self, color, money_value=0):
        super().__init__(color, money_value=money_value)

class MoneyCard(Card):
    def __init__(self, money_value=0):
        super().__init__(money_value=money_value)

เนื่องจากPythonเป็นภาษาที่พิมพ์แบบไดนามิกOOPจึงยากที่จะพิสูจน์ความคิดเห็นของฉันเนื่องจากเราสามารถพึ่งพาการพิมพ์เป็ดและการเชื่อมโยงแบบไดนามิกวิธีที่คุณจัดลำดับชั้นของคุณมีความสำคัญน้อยกว่า

ถ้าฉันทำแบบจำลองปัญหานี้ในC #ฉันจะใช้ลำดับชั้นที่แสดงไว้ข้างต้นอย่างไม่ต้องสงสัยเพราะฉันสามารถพึ่งพาpolymorphismเพื่อแสดงชนิดต่าง ๆ และแนะนำการไหลของตรรกะของฉันตามชนิดของบัตรที่กำลังวิเคราะห์

ข้อสังเกตสุดท้าย:

  1. Pythonมีประเภทบิวด์อินที่ทรงพลังมาก แต่ส่วนใหญ่ใช้แบบกำหนดเองใหม่ที่สร้างขึ้นมาเพื่อทำให้ชีวิตของคุณง่ายขึ้น
  2. คุณไม่ต้องรับช่วงobjectตั้งแต่ในPython 3 (ซึ่งเป็นรุ่นเดียวที่ได้รับการบำรุงรักษาในวันนี้) สืบทอดมาจากobjectค่าเริ่มต้น

แต่ในตอนท้ายของวันนั้นไม่มีคำตอบที่สมบูรณ์แบบวิธีที่ดีที่สุดคือการลองใช้ทั้งสองวิธีและดูว่าคุณพอใจกับอะไรมากขึ้น


7

นี่คือสิ่งที่เราเรียกว่า "การตัดสินใจออกแบบ" บ่อยครั้งวิธีที่ "ถูกต้อง" เป็นเรื่องของความคิดเห็น ในฐานะผู้เริ่มต้นฉันคิดว่ามันจะเป็นคำแนะนำในการลองใช้ทั้งสองเพื่อดูว่าพวกเขาทำงาน จะมีการแลกเปลี่ยนไม่ว่าคุณจะเลือกแบบใด คุณต้องตัดสินใจว่าการแลกเปลี่ยนใดที่สำคัญที่สุด การตัดสินใจประเภทนี้จะแจ้งให้ทราบเมื่อคุณได้รับประสบการณ์มากขึ้น


ใช่ขอบคุณฉันทำตามที่คุณพูดเพียงแค่มองหาคำแนะนำจากคนที่มีประสบการณ์มากพอที่จะรู้วิธีที่ดีและหวังว่าจะเข้าใจว่าทำไม
teeeeee

2

คุณสามารถใช้มรดก นี่คือที่ที่คุณสร้างคลาสหลักจากนั้นมีคลาสย่อยซึ่งยังคงมีฟังก์ชั่นและค่าจากคลาสแม่ แต่ยังสามารถมีค่าและฟังก์ชั่นพิเศษสำหรับคลาสเฉพาะนั้น

class Apple:
    def __init__(self, yearMade):
        pass

    def ring(self):
        print('ring ring')

class iPhone(Apple):
    def __init__(self, number)
        number = number

    def func():
        pass

ตอนนี้คลาส iPhone มีฟังก์ชั่นเช่นเดียวกับคลาส Apple และฟังก์ชั่นของตัวเอง หากคุณต้องการเรียนรู้เพิ่มเติมเกี่ยวกับมรดกฉันขอแนะนำให้ทำการวิจัย


@teeeeee เนื่องจากบัตรแต่ละใบมีมูลค่าคุณสามารถแลกเปลี่ยนและเล่นได้คุณสามารถสร้างฟังก์ชั่น / ขั้นตอนในชั้นเรียนเพื่อจัดการเหตุการณ์เหล่านี้แล้วมีคุณสมบัติและฟังก์ชั่นพิเศษสำหรับการ์ดบางประเภทในคลาสย่อย
MoriartyPy

0

สำหรับการผูกขาดฉันจะออกแบบมุมมองของเกม ไม่ใช่บัตร การ์ดเป็นตัวแทนของการลงจอดเพื่อโลกแห่งความจริง


กรุณาอธิบายอย่างละเอียด
ตี๋
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.