Рок бумаги ножницы в Python


Я новичок в Python и начали объектно-ориентированное программирование в последнее время. Я реализовал "Камень-Ножницы-Бумага" заявление в ООП. Я бы хотел, чтобы вы оценить мой код, и скажите мне, где я могу улучшить мой код и как я могу лучше организовать функциональность.

import random

class RockPaperScissors(object):        
    def setUserOption(self,val):
        self.__option = val

    def getValueFromList(self,option):
        l = ['rock','scissors','paper']
        return l[option]

    def __getRandomValue(self,max):
        val = random.randint(1,max)
        return self.getValueFromList(val-1)

    def __getResult(self,t):
        self.__d = {('rock','scissors'):'rock breaks scissors - User has won',('rock','paper'):'rock is captured by paper - User has won',('scissors','paper'):'Scissors cut paper - User has won',
                    ('scissors','rock'):'rock breaks scissors - Computer won',('paper','rock'):'rock is captured by paper - Computer won',('paper','scissors'):'Scissors cut paper - Computer won'}
        return self.__d[t]

    def __computeResult(self,computerOption):
        if computerOption == self.__option:
            return 'The user and computer choose the same option'
        else:
            return self.__getResult((self.__option,computerOption))

    def printResult(self):
        computerOption = self.__getRandomValue(3)
        print 'User choice: ',self.__option
        print 'Computer choice: ',computerOption
        print self.__computeResult(computerOption)

if __name__ == "__main__":
    print 'Welcome to rock paper scissors'
    print '1. Rock, 2. Paper, 3. Scissor'
    val = int(raw_input('Enter your choice Number: '))
    if val >=1 and val <= 3:
        obj = RockPaperScissors()
        obj.setUserOption(obj.getValueFromList(val-1))
        obj.printResult()
    else:
        raise ValueError('You are supposed to enter the choice given in the menu')


Комментарии
7 ответов

Эти ответы являются фантастическими, но, кажется, сосредоточиться на одной стороне вашего вопроса. Я собираюсь сосредоточиться на ориентации объекта.

Я пересмотрел свой код с парой основных понятий в разуме, а именно полиморфизм и инкапсуляция.

Полиморфизм

Где находятся ваши объекты? Рок, бумага, ножницы и все могут быть объекты, они не могли? И, самое главное, они все же объект. Они все "куски" игры.

Вот псевдо-пример:

class Rock inherits from Element
type = 'rock'
def compare(Element)
if type == 'paper'
return 'LOSE'
elsif type == 'scissors'
return 'WIN'
else
return 'TIE'

Хотя это потенциальное решение, мой пример будет идти в другом направлении просто за то, что если вы хотели, чтобы добавить больше элементов, тогда тебе придется трогать уже существующий код (на примере Криса из RPSLS).

Инкапсуляция

Многие мышцы программирования тренировки является инкапсуляция. Два основных направления, в этом примере, чтобы скрыть пользовательский интерфейс от кода игры.

Пользовательский интерфейс не должен заботиться о внутреннем устройстве игры. В игре не должно волновать, как она отображается. Что делать, если хочется сменить интерфейс на что-то более графическое? Прямо сейчас, ваш код полагается на консоль, чтобы знать о части игры и как это работает.

Пример

Итак, вернемся к примеру Криса снова. Элементы этой игры является то, что они могут довольно часто меняться. Как вы можете справиться с этим в будущем программировать легче?

Одним из решений является магазин "данные" из игры в другом месте и динамически создавать объекты.

Следующий код на Python, чтобы воплотить в жизнь идеи, которые я написал здесь.

Код вот на абстрактную часть игры, элемент:

# The goal for an element is to just know when it wins, when it loses, and how to figure that out.
class Element:
_name = ""
_wins = {}
_loses = {}

def get_name(self):
return self._name

def add_win(self, losingElementName, action):
self._wins[losingElementName] = action

def add_loss(self, winningElementName, action):
self._loses[winningElementName] = action

def compare(self, element):
if element.get_name() in self._wins.keys():
return self._name + " " + self._wins[element.get_name()] + " " + element.get_name()
elif element.get_name() in self._loses.keys():
return None
else:
return "Tie"

def __init__(self, name):
self._name = name
self._wins = {}
self._loses = {}

Игры игроков:

# The player's only responsibility is to make a selection from a given set. Whether it be computer or human.
class Player:
_type = ''
_selection = ''

def make_selection(self, arrayOfOptions):
index = -1
if (self._type == 'Computer'):
index = random.randint(0, len(arrayOfOptions) - 1)
else:
index = int(raw_input('Enter the number of your selection: ')) - 1
self._selection = arrayOfOptions[index]
return self._type + ' selected ' + self._selection + '.'

def get_selection(self):
return self._selection

def __init__(self, playerType):
self._type = playerType
self._selection = ''

Код игры:

# A game should have players, game pieces, and know what to do with them.
class PlayGame:
_player1 = Player('Human')
_player2 = Player('Computer')

_elements = {}

def print_result(self, element1, element2):
val = element1.compare(element2)
if (val != None):
print "YOU WIN! (" + val + ")" # win or tie
else:
print "You lose. (" + element2.compare(element1) + ")"

def fire_when_ready(self):
counter = 1
for e in self._elements.keys():
print str(counter) + ". " + e
counter = counter + 1
print ""
print "Shoot!"
print ""

print self._player1.make_selection(self._elements.keys())
print self._player2.make_selection(self._elements.keys())

element1 = self._elements[self._player1.get_selection()]
element2 = self._elements[self._player2.get_selection()]

self.print_result(element1, element2)

def load_element(self, elementName1, action, elementName2):
winningElementObject = None
newElementObject = None

if (elementName1 in self._elements):
winningElementObject = self._elements[elementName1]
winningElementObject.add_win(elementName2, action)
else:
newElementObject = Element(elementName1)
newElementObject.add_win(elementName2, action)
self._elements[elementName1] = newElementObject

if (elementName2 in self._elements):
losingElementObject = self._elements[elementName2]
losingElementObject.add_loss(elementName1, action)
else:
newElementObject = Element(elementName2)
newElementObject.add_loss(elementName1, action)
self._elements[elementName2] = newElementObject

def __init__(self, filepath):
# get elements from data storage
f = open(filepath)
for line in f:
data = line.split(' ')
self.load_element(data[0], data[1], data[2].replace('\n', ''))

Код консоли пользовательского интерфейса:

if __name__ == "__main__":
print "Welcome"
game = PlayGame('data.txt')
print ""
print "Get ready!"
print ""
game.fire_when_ready()

И файл данных, data.txt:

scissors cut paper
paper covers rock
rock crushes lizard
lizard poisons spock
spock smashes scissors
scissors decapitates lizard
lizard eats paper
paper disproves spock
spock vaporizes rock
rock crushes scissors

Целью моего ответа было показать вам, как можно использовать некоторые концепции объектно-ориентированного программирования в решении вашей проблемы. При этом я также оставил некоторые нерешенные проблемы. Одно заключается в том, что игрок и игровые объекты по-прежнему в сочетании с пользовательским интерфейсом. Один способ красиво решить это будет с помощью делегатов.

11
ответ дан 28 апреля 2011 в 04:04 Источник Поделиться

Все в всех, ты отлично выглядишь!

Вот несколько вещей, которые выделяются для меня:


  • Вы используете дважды подчеркнуть название
    коверкание, когда вы, вероятно, не
    нужно. Это не самая лучшая привычка
    попасть. Один-подчеркивают говорит: "Я
    я частная" без
    ужасные запутывания имя. Рассмотрим
    переименования __метод()к
    Http, то().

  • Внутри __метод getresult()вы
    определение __д. Это означает, что каждый раз
    этот метод вызывается, что
    словарь воссоздается. Это
    наверное, не то, что вы хотите.
    Рассмотреть вопрос о переходе к классу
    атрибут

  • Ваш способ (и какой-либо переменной) имена mixedCase,
    который нарушает Конвенцию Python в
    соответствии с питона стиль
    Гид
    (он же ПЭП 8). Рассмотрим
    изменение их
    lower_case_with_underscores.

7
ответ дан 26 апреля 2011 в 08:04 Источник Поделиться

Я согласен с jathanism - это выглядит очень хорошо. Это хорошо организованы и не слишком много.

Вам выдаст ошибку, если выбран неверный вариант. Вы рассматривали цикл, пока вы не Выберите правильное значение?

val = 0
while val < 1 and val > 3
val = int(raw_input('Enter your choice Number: '))

Также, вы перекладываете значение вниз, чтобы компенсировать 0 относительная массива. Я бы рекомендовал изменение массива искусственно 1-относительные:

l = ['dummy', 'rock', 'paper', 'scissors']

В качестве альтернативы вы могли бы сделать переключение внутри getValueFromList. Не заставляйте звонящего, хотя сделать это - они не должны беспокоиться о таких вещах. Кроме того, вы должны сделать некоторые проверки границ - что происходит, когда кто-то называет getValueFromList(5)? Что может быть правильным местом, чтобы бросить ValueError.

4
ответ дан 26 апреля 2011 в 08:04 Источник Поделиться

Наряду с комментариями @jathanism, я бы добавил следующее:

Я хотел перенести определение списка параметров в переменную класса, например:

class RockPaperScissors(object):
OPTIONS=['rock','paper','scissors']
...

таким образом, когда вы хотите продлить игру на RockPaperScissorsLizardSpock, вы можете сделать это с простой inheiritance:

class RockPaperScissorsLizardSpock(RockPaperScissors):
OPTIONS=['rock','paper','scissors','lizard','spock']
...

Очевидное расширение/продолжение этого комментария заключается в том, что __метод getresult бы тогда должны быть обновлены, чтобы быть более общим в базовом классе.

Кроме того, логика для печати/выделения затем могут быть основаны на "опции" постоянный. (например: печать ', '.присоединяйтесь к( '%ы. на %S' % (Я,V) для меня в перечисление(RockPaperScissors.Варианты) )). Еще лучше, поставить логику выделение в метод класса.

Я стараюсь применять эти понятия для большинства классов, так как 1) он не очень больше усилий для реализации, и 2) она позволяет подклассам легко переопределять поведение базового класса, даже если вы не ожидаете наследства, чтобы быть использованы.

4
ответ дан 26 апреля 2011 в 08:04 Источник Поделиться

Ваша случайная функция:

def __getRandomValue(self,max):
val = random.randint(1,max)
return self.getValueFromList(val-1)


  1. Вы только когда-нибудь вызвать эту функцию с Максом = 3, так как это единственный разумный довод только предположить, что и не вызывающий передать его

  2. Вы выбираете случайное значение между 1 и Max, а потом вычесть один. Лучше выбрать значение между 0 и Max-1 (случайные.randrange сделать это легко)

  3. Если вы делаете список л атрибут класса, так как Крис предполагает, то вы можете использовать случайный.выбор выбрать вариант.

3
ответ дан 27 апреля 2011 в 12:04 Источник Поделиться

Поздравляем. Ты все успел записать Java на Python.

Попробуйте что-то вроде:

from random import choice
if __name__ == "__main__":
while True:
print "1. Rock 2. Paper 3. Scissors"
val, comp = int(raw_input('Enter your choice Number: ')), choice(range(1,4))
if val == comp:
print "Draw. Try again"
elif val == 1:
if comp == 2:
print "You lose"
if comp == 3:
print "#WINNING"
elif val == 2:
if comp == 3:
print "You lose"
if comp == 1:
print "#WINNING"
elif val == 3:
if comp == 2:
print "You lose"
if comp == 1:
print "#WINNING"

Это, даже с невероятно длинным, если/другое заявление, это лучше, чем все предложенные здесь.

3
ответ дан 29 января 2012 в 07:01 Источник Поделиться

Было бы более подходящие для Python, чтобы использовать свойства (или открытые поля, если вам не нужно каких-либо специальных геттер/сеттер логики), а не методы геттер/сеттер.

1
ответ дан 26 апреля 2011 в 08:04 Источник Поделиться