2010-09-16 37 views
6

Vì vậy, tôi có mã này cho một đối tượng. Đối tượng đó là một động thái mà bạn có thể thực hiện trong một trò chơi của scissor giấy. Bây giờ, đối tượng cần phải là cả số nguyên (để khớp một giao thức) và một chuỗi để thuận tiện cho việc viết và xem.Làm cách nào để tạo mã này Pythonic

class Move: 
    def __init__(self, setMove): 
     self.numToName = {0:"rock", 1:"paper",2:"scissors"} 
     self.nameToNum = dict(reversed(pairing) for pairing in self.numToName.items()) 
     if setMove in self.numToName.keys(): 
      self.mMove=setMove 
     else: 
      self.mMove=self.nameToNum.get(setMove) #make it to a number 

    def defeats(self): 
     return Move((self.mMove-1)%3) 
    def losesTo(self): 
     return Move((self.mMove+1)%3) 
    def tiesWith(self): 
     return self 

    #Operator overloading 
    def __eq__(A,B): 
     return A.mMove==B.mMove 
    def __gt__(A,B): 
     return A.defeats(B) 
    def __lt__(A,B): 
     return A.losesTo(B) 
    def __ge__(A,B): 
     return A>B or A==B 
    def __le__(A,B): 
     return A<B or A==B 

    def __str__(self): 
     return self.numToName.get(self.mMove); 

    def __int__(self): 
     return self.mMove; 

Bây giờ, tôi mới bắt đầu từ python, đến từ nền C và Java. Một điều lớn trong python là chỉ có một cách chính xác để làm điều gì đó. Một điều khác không đáng lo ngại về loại. Tôi khá lo lắng về loại hình ở đây.

Vì vậy, tôi không chắc chắn cách xử lý đúng các đối tượng này là gì. Hiện tại tôi có một đối tượng là một trong ba loại (hoặc nhiều hơn nhưng tôi không chắc chắn điều đó sẽ làm gì) Có lẽ thay vào đó tôi nên sử dụng các đối tượng của các lớp khác nhau? và làm cho họ đơn? Ngoài ra đối tượng của tôi hiện đang có thể sửa đổi sau khi sáng tạo, đó là một điều xấu trong tâm trí của tôi.

Vì vậy, đây là mã Pythonic, và làm thế nào tôi có thể làm cho nó thanh lịch hơn? (Tôi hình dung đây là một ví dụ tốt để sử dụng, để giúp tôi tìm ra điều gì làm cho mã python tốt. Xin lỗi nếu có vẻ như đã mở một chút)

+0

Nếu bạn muốn understan d thêm về các vấn đề thực tế/trò chơi: http://progcomp.ucc.asn.au/FrontPage Chuyển động là một điều nhỏ tôi chỉ ngẫu nhiên nghĩ rằng tôi có thể muốn tạo một kiểu cho, như là một cách tốt hơn để kìm nén chúng. –

Trả lời

11

Với tôi, khái niệm mã là "pythonic" thực sự đi xuống với ý tưởng rằng khi bạn hiểu vấn đề bạn đang cố gắng giải quyết, mã gần như tự viết. Trong trường hợp này, không lo lắng về việc trừu tượng sâu hơn về người chơi, trò chơi, ném, v.v., bạn có vấn đề sau: có một số loại di chuyển nhất định, mỗi loại có tên, với các quy tắc được đặt di chuyển, và bạn cần phải tìm một cách để xác định di chuyển và tìm ra di chuyển thắng trong một so sánh.Khi tôi đọc mã của bạn, tôi không thấy ngay vấn đề này, tôi thấy rất nhiều suy nghĩ khác đã đi vào chính mã, tìm kiếm các biểu diễn kiểu, thực hiện các thủ thuật số học, và thường buộc vấn đề vào một khung mã , thay vì cách khác. Vì vậy, tôi muốn đề xuất một cái gì đó như:


class Move: 
    TYPES = ['rock', 'paper', 'scissors'] 
    BEATS = { 
    'rock': ['scissors'], 
    'paper': ['rock'], 
    'scissors': ['paper'] 
    } 

    def __init__(self, type): 
    if type not in self.TYPES: 
     raise Exception("Invalid move type") 
    self.type = type 

    def __str__(self): 
    return self.type 

    def __cmp__(self, other): 
    if other.type in self.BEATS[self.type]: 
     return 1 
    elif self.type in self.BEATS[other.type]: 
     return -1 
    else: 
     return 0 

Và bạn đã hoàn tất. Bạn có thể ném vào tất cả các accessors khác, vv nhưng nó thực sự chỉ đóng băng, vấn đề cốt lõi được giải quyết và mã có thể đọc được, linh hoạt, dễ mở rộng, vv Đó thực sự là những gì tôi nghĩ "pythonic" có nghĩa là.

+1

và nếu bạn thực sự cần số nguyên, hãy sử dụng: def __int __ (tự): tự trả lại.TYPES.index (self.type) – gmarcotte

2

Vâng, bạn chỉ có ba bước di chuyển đúng không? Tại sao không chỉ đại diện cho họ như là chuỗi? Có vẻ như lý do duy nhất bạn có các con số là thực hiện các so sánh (nghĩa là những thất bại nào) với một số phép toán "thông minh", nhưng thành thật mà nói tôi không nghĩ nó xứng đáng. Tất cả các bạn thực sự cần là một chức năng để xác định cái nào là người chiến thắng trong mỗi so sánh có thể:

def winner(move0, move1): 
    if move0 == move1: 
     return None 
    elif (move0 == 'rock' and move1 == 'scissors') or \ 
     (...paper vs. rock...) or \ 
     (...scissors vs. paper...): 
     return 0 
    else: 
     return 1 

Tôi chỉ cần thực hiện lên sự trở lại giá trị None, 0, và 1 làm ví dụ, bạn có thể sử dụng bất cứ điều gì là thích hợp cho hoàn cảnh của bạn.

"Đơn giản là tốt hơn phức tạp", Zen của dòng Python 3 ;-)

+0

như tôi đã nói. "Tôi cần các số nguyên cho phù hợp với một giao thức" Có những thứ khác trên thế giới đang ném di chuyển như tôi, và tôi ném di chuyển, và cơ chế bạn biết những gì đang được thực hiện cho bạn là giao thức này dựa trên những con số đó. Đố chỉ dành cho sự kiên nhẫn. –

+0

OK, tốt nếu chúng phải là số nguyên, chỉ cần sử dụng số nguyên thay vì chuỗi, tức là thay thế ''rock'' ->' 0' vv trong câu trả lời của tôi. Nó không thực sự thay đổi bất cứ điều gì. Nếu bạn muốn in ra một chuỗi đại diện, cho một cái gì đó đơn giản này tôi chỉ có thể thực hiện một chức năng để trả về chuỗi tương ứng với một di chuyển nhất định: 'def as_string (di chuyển): return {0:" rock ", 1:" paper " , 2: "kéo"} [di chuyển] ' –

0

Tôi không chắc chắn trò chơi được tóm tắt đủ tốt. Một động thái là một sự kiện có hai người chơi. Nói cách khác, một động thái không phải là một cầu thủ, và người chơi không phải là một động thái. Bạn nghĩ gì về điều này:

# notice that the element k+1 defeats element k 
THROWS = ['paper', 'scissors', 'rock'] 

class Player(object): 
    def __init__(self, name, throws): 
    # name the player 
    self.name = name 
    # the throws are contained a priori 
    self.throws = throws 

    def throw(self): 
    # a throw uses (and removes) the first element of the throws 
    # list 
    return self.throw_value(self.throws.pop(0)) 

    def throw_value(self, what): 
    if what in [0,1,2]: 
     # if the throw is a legal int, return it 
     return what 
    if what in THROWS: 
     # if the throw is a legal str, return the 
     # corresponding int 
     return THROWS.index(what) 
    # if none of the above, raise error 
    raise ValueError('invalid throw') 

class Game(object): 
    def __init__(self, player_1, player_2): 
    # a game has two players 
    self.player_1 = player_1 
    self.player_2 = player_2 

    def go(self, throws=3): 
    # a "go" of the game throws three times 
    for _ in range(throws): 
     print self.throw() 

    def throw(self): 
    # a throw contains the rules for winning 
    value_1 = self.player_1.throw() 
    value_2 = self.player_2.throw() 

    if value_1 == value_2: 
     return 'draw' 

    if value_1 > value_2: 
     return self.player_1.name 

    return self.player_2.name 

if __name__ == "__main__": 
    juan = Player("Juan", ['rock', 0, 'scissors']) 

    jose = Player("Jose", [1, 'scissors', 2]) 

    game = Game(juan, jose) 

    game.go() 
+0

Chưa đọc mã của bạn dù chặt chẽ, Nhưng có, một động thái không phải là một cầu thủ. Trò chơi đang được chạy bởi một ứng dụng khác, Người chơi có thể được viết bằng bất kỳ ngôn ngữ nào. Họ liên lạc với Trò chơi với số 0,1,2 trên stdio. Trò chơi cho họ biết sau đó họ đã thắng hoặc thua. Xem: http://progcomp.ucc.asn.au/FrontPage Tôi chỉ cần tạo một lớp di chuyển để sử dụng nội bộ để theo dõi cách những Người chơi khác hành xử –

+0

Giải pháp mà tôi đề xuất cũng hoạt động trong trường hợp đó. Giao diện của "GAME" hoạt động bất kể ai di chuyển người chơi. – Escualo

1
mv = {"Scissor":0, "Rock":1, "Paper":2} 
def winner(m1, m2): 
    result = "Tie" if m1 == m2 else max(m1, m2) if abs(m1 - m2) != (len(mv) - 1) else min(m1, m2) 
    return mv.keys()[mv.values().index(result)] if result in mv.values() else result 

tôi đã viết này để chứng minh khái niệm: với 5 dòng và hầu như không có định hướng đối tượng bạn có thể đạt được kết quả ghi, giấy; đá; cắt kéo.

Từ điển số/chuỗi. Nếu bạn chuyển số vào, kết quả của bạn sẽ là tên của chuỗi chiến thắng. Hiệu lực của chiến thắng là tuần tự (một < b < c < a) vì vậy bạn có thể chỉ cần thực hiện kiểm tra khoảng cách để xác định nhu cầu ghi đè chuỗi. Tôi đã thêm "Tie" vì đó là trường hợp hiển nhiên nhưng thực sự xây dựng trò chơi với người chơi và tất cả đều tầm thường với phương pháp này. Bây giờ nếu bạn muốn chơi Paper, Rock, Scissors, Lizard, Spock, chúng tôi sẽ cần phải refactor.

+0

Rất tiếc. Tôi giống như thế này, miễn là tôi không phải giải thích nó làm gì mà không biết trước những gì nó làm. ;) –

+0

Nên có một-- và tốt nhất là chỉ có một - cách rõ ràng để làm điều đó. Mặc dù cách đó có thể không rõ ràng lúc đầu trừ khi bạn là người Hà Lan. – Gabriel

2

Dưới đây là một phiên bản ngắn cho biết kết quả bằng lời nói.

def winner(p1, p2): 
    actors = ['Paper', 'Scissors', 'Rock'] 
    verbs = {'RoSc':'breaks', 'ScPa':'cut', 'PaRo':'covers'} 
    p1, p2 = actors.index(p1), actors.index(p2) 
    winner, looser = ((p1, p2), (p2, p1))[(1,0,1)[p1 - p2]] 
    return ' '.join([actors[winner], 
        verbs.get(actors[winner][0:2] + actors[looser][0:2], 
           'ties'), 
        actors[looser]]) 

Lợi ích của cấu trúc này là điều hiển nhiên khi mở rộng để bao gồm Rock, Paper, Scissors, Lizard, Spock

def winner(p1, p2): 
    actors = ['Paper', 'Scissors', 'Spock', 'Lizard', 'Rock'] 
    verbs = {'RoLi':'crushes', 'RoSc':'breaks', 'LiSp':'poisons', 
      'LiPa':'eats', 'SpSc':'smashes', 'SpRo':'vaporizes', 
      'ScPa':'cut', 'ScLi':'decapitate', 'PaRo':'covers', 
      'PaSp':'disproves'} 
    p1, p2 = actors.index(p1), actors.index(p2) 
    winner, looser = ((p1, p2), (p2, p1))[(1,0,1,0,1)[p1 - p2]] 
    return ' '.join([actors[winner], 
        verbs.get(actors[winner][0:2] + actors[looser][0:2], 
           'ties'), 
        actors[looser]]) 

>>> winner("Rock", "Scissors") 
'Rock breaks Scissors' 
>>> winner("Rock", "Spock") 
'Spock vaporizes Rock' 
>>> winner("Spock", "Paper") 
'Paper disproves Spock' 
>>> winner("Lizard", "Scissors") 
'Scissors decapitate Lizard' 
>>> winner("Paper", "Paper") 
'Paper ties Paper' 
+0

+1 - Kết quả tổng quát là khá tốt. Đặc biệt là động từ. – Geoff

Các vấn đề liên quan