Golf Me A ООП!

26

Golf Me A ООП!

Двумя важными компонентами объектно-ориентированного программирования являются наследование и компоновка. Вместе они позволяют создавать простые, но мощные иерархии классов для решения проблем. Ваша задача - проанализировать ряд утверждений об иерархии классов и ответить на вопросы об иерархии.

вход

Серия утверждений и вопросов об иерархии классов, прочитанных из файла или стандартного ввода, в зависимости от того, что лучше для вашего языка. Если вы используете опцию file, имя файла будет передано в качестве первого аргумента в ваш код (аргумент функции или аргумент командной строки, в зависимости от того, что вы выберете). Формат выглядит следующим образом:

<statement> : <name> is a <name>. | <name> has a <name>.
<question> : Is <name> a <name>? | Does <name> have a <name>?
<name> : a-z | A-Z | sequence of alphanumerics or underscores, starting with a letter

На входе всегда будут заявления, а затем вопросы. Все имена классов начинаются с заглавной английской буквы ( A-Z), а все имена членов начинаются со строчной английской буквы ( a-z). Все имена чувствительны к регистру - ABC123это не тот же класс, что и Abc123.

Не будет никакого циклического наследования - если Bнаследует от A, Aне наследует от Bкого-либо из Bдетей.

Только имена классов будут частью иерархии - такие операторы, как foo is a bar.или document has a name.не будут встречаться.

Выход

Ряд истинных или ложных значений, как ответы на запросы, записанные в стандартный вывод или как возвращаемое значение вашей функции. Если у вас недостаточно информации для ответа на вопрос (например, вопросы с именами, которых вы не видели в утверждениях), ответьте с ошибочным значением.

Тестовые случаи

Случай 1:

Входные данные:

B is a A.
C is a B.
A has a foo.
Does B have a foo?
Is C a A?
Is D a A?

Выход:

True
True
False

Случай 2:

Входные данные:

Cop is a Person.
Criminal is a Person.
Sheriff is a Cop.
Crooked_Cop is a Cop.
Crooked_Cop is a Criminal.
BankRobber is a Criminal.
Cop has a badge.
Criminal has a criminal_record.
Person has a name.
Is Crooked_Cop a Person?
Does Criminal have a name?
Is Crooked_Cop a BankRobber?
Does Person have a potato?
Is Cop a Cop?

Выход:

True
True
False
False
True

правила

  • Вы можете ответить с помощью функции или программы
  • Стандартные лазейки запрещены
  • Это , поэтому выигрывает кратчайший правильный ответ в байтах
  • Победивший ответ будет выбран через неделю

Удачи, и да будет с вами ООП!

Leaderboard

Фрагмент стека в нижней части этого поста создает таблицу лидеров из ответов а) в виде списка кратчайшего решения для каждого языка и б) в качестве общей таблицы лидеров.

Чтобы убедиться, что ваш ответ обнаружен, начните его с заголовка, используя следующий шаблон уценки:

## Language Name, N bytes

где Nразмер вашего представления. Если вы улучшите свой счет, вы можете сохранить старые результаты в заголовке, вычеркнув их. Например:

## Ruby, <s>104</s> <s>101</s> 96 bytes

Если вы хотите включить в заголовок несколько чисел (например, потому что ваш результат равен сумме двух файлов или вы хотите перечислить штрафы за флаг интерпретатора отдельно), убедитесь, что фактический результат является последним числом в заголовке:

## Perl, 43 + 2 (-p flag) = 45 bytes

Вы также можете сделать имя языка ссылкой, которая будет отображаться во фрагменте кода:

## [><>](http://esolangs.org/wiki/Fish), 121 bytes

Mego
источник
Как Does Criminal have a name?равняется True? У всех объектов есть имя?
Дж Аткин
4
@JAtkin Criminal is a Person. Person has a name,
Рето Коради
Ааа ... Я пропустил это.
Дж Аткин
Нужно ли мне принимать все входные данные одновременно или я могу принимать их построчно, как интерактивную консоль? Если # 2, могу ли я вывести правдивый \ фальси, даже если вход является комментарием?
Дж Аткин
@JAtkin Все сразу или построчно, на ваш выбор. Если это утверждение, не должно быть никакого вывода. Только вопросы получают ответы.
Мего

Ответы:

13

CJam, 59 байт

q_'.e=\N/{)'?=\S/>_,(%}%/(__,*{(2$z~@f=.*\m*|}/ff{1$e=>:=N}

Это завершается мгновенно для обоих тестовых случаев.

Он либо печатает второе имя имени вопроса либо 1(оба правдиво), либо 0(ложно).

Попробуйте онлайн в интерпретаторе CJam .

идея

Из-за различий между классами и членами задача сводится к созданию предварительного заказа, для которого входные данные предоставляют частичное определение.

Мы определим, что xy, если x является y или x имеет y .

Для первого контрольного примера вход указывает, что BA , CB и Afoo . Из-за транзитивности у нас также есть Bfoo , CA и Afoo . Кроме того, из-за рефлексивности, xx всегда верно.

Таким образом, для данного ввода мы можем извлечь частичное определение ≺ из утверждений, применить транзитивность достаточное количество раз, чтобы завершить определение ≺ и, наконец, ответить на вопросы.

Код

q_     e# Push all input from STDIN and a copy.
'.e=   e# Count the number of dots/statements (C).
\N/    e# Split the original input at linefeeds.
{      e# For each line:
  )'?= e#   Pop the last character and check if it is a question mark.
       e#   Pushes 1 for '?', 0 for '.'.
  \S/  e#   Split the modified line at spaces.
  >    e#   Remove the first chunk ("Does" or "Is") for questions.
  _,(% e#   Keep the first and last element of the resulting array.
}%/    e# Split the line array into chunks of length C.
(_     e# Extract the first chunk (statements) and push a copy.
       e# The original becomes an accumulator for ≺.
_,*    e# Repeat the statements C times.
{      e# For each of the repeated statements:
  (    e#   Shift out the first name.
       e#     ["w" "x"] -> ["x"] "w"
  2$z~ e#   Copy the accumulator, zip it and dump.
       e#     [["x" "y"] ["z" "w"]] -> ["x" "z"] ["y" "w"]
  @f=  e#   Rotate the shifted out name on top and check for equality.
       e#     ["y" "w"] "w" -> [0 1]
  .*   e#   Vectorized string repetition.
       e#     ["x" "z"] [0 1] -> ["" "z"]
  \m*  e#   Swap the result with the shifted array and apply Cartesian product.
       e#     ["" "z"] ["x"] -> [["" "x"] ["z" "x"]]
       e#   This accounts for transitivity; we had ["w" "x"] and ["z" "w"],
       e#   so now we have ["z" "x"].
  |    e#   Perform set union with the accumulator to add the new pairs.
}/     e#
ff{    e# For each of the questions on the bottom of the stack.
  1$e= e#   Count the occurrences of the question pair in the accumulator.
  >    e#   Remove 0 or 1 elements from the question pair.
  :=   e#   Check for equality.
       e#   If the question pair occurs in the accumulator, this pushes the
       e#   second name of the question pair. Otherwise, it pushes 1 if the
       e#   names are equal (to account for reflexivity) and 0 otherwise.
  N    e#   Push a linefeed.
}      e#
Деннис
источник
2
Это впечатляет, если учесть, что у CJam нет уроков: D
Beta Decay
Это прекрасно.
Мего
@BetaDecay Классы - это по сути вложенные множества; классы реализованы на каждом языке. Скажи в первом примере. C:{B:{A:{foo:{}}}}
8

Python 3, 431 331 308 байт

o={}
f={}
def h(z,f):
 if z not in o:f[z]=[z];o[z]=[]
while 1:
 g=input().split(' ');r=2;l=g[-1][:-1]
 if'.'in g[3]:
  if'i'in g[1]:h(g[0],f);h(l,f);f[g[0]]+=f[l]
  if'h'in g[1]:o[g[0]]+=l,
 else:
  if'I'in g[0]:r=any(l in z for z in f[g[1]])
  if'D'in g[0]:r=any(l in o[z] for z in f[g[1]])
 if r<2:print(r)

Это полная версия с комментариями

objects = {}
synonyms = {}

def createObject(name):
    """
    Create a object with `name` if is does not yet exist and start a synonym tree.
    """
    if name not in objects:
        synonyms[name] = [name]
        objects[name] = []

# use this to read from a file
# with open("questions.txt") as file: 
#     for l in file:
        # print(">>> " + l, end='')
        # inArg = l.replace("\n","").split(" ")


while True: # to read from a file comment this
        inArg = input(">>> ").split(" ") # and this out

        out = -1

        if '.' in inArg[3]: # statement
            last = inArg[3].replace('.','')

            if 'i' in inArg[1]: # is a
                createObject(inArg[0])
                createObject(last)
                synonyms[inArg[0]] += synonyms[last]

            if 'h' in inArg[1]: # has a
                objects[inArg[0]] += [last]

        else:# question
            last = inArg[-1].replace('?','')

            createObject(inArg[1])
            if 'I'in inArg[0]: # Is a
                out = any([last in syn for syn in synonyms[inArg[1]]])

            if 'D'in inArg[0]: # Does have a
                out = any(last in objects[syn] for syn in synonyms[inArg[1]])

        if out != -1:
            print(out)

Выход для теста № 1:

True
True
False

Дело № 2:

True
True
False
False
True

Я удалил команды отладки для ясности в основной программе, но если вы хотите увидеть их, просто посмотрите в историю

Дж Аткин
источник
Вместо использования global fin h(z), используйте def h(z,f)и передавайте глобальный fin при вызове. На самом деле, вам совсем не нужно h(z)- просто поместите тело туда, где вы его называете. Вам не нужно r=2, и вы можете просто обойтись print(r)без if, так как вам нужно вывести значение Falsey для ложных запросов. Вы можете переименовать synв zи сбрить несколько байт там. Я не думаю, что вам нужно во []всем вашем понимании списка в первую очередь any.
Мего
Вы также используете eодин раз, так что вы можете покончить с определением и просто использовать [a,b,c,d]. Вместо if s(i,g) is not Nonedo if s(i,g)- re.Matchобъекты всегда оцениваются, Trueесли найдено совпадение. Вы также можете сбросить 2 байта с помощью f[x]+=f[y].
Мего
@Mego Wow, спасибо за все советы. Я должен положить их позже.
Дж Аткин
Этот пост , вероятно, очень вам поможет
Mego
@Mego Большое спасибо, сейчас до 396. Я отправлю в ближайшее время.
Дж Аткин
4

Haskell, 157 байт

o s=v(x 0#k)#(x 1#q)where(k,q)=break((=='?').l.l)(words#lines s)
x n w=(w!!n,init$l w)
v k(a,c)=a==c||or[v k(b,c)|b<-snd#(filter((==a).fst)k)]
(#)=map
l=last

Дайте строку для o. Не уверен, что создание инфиксов xи v('extract' и 'verify') режет больше, чем создание mapинфикса, или оба варианта возможны.

РЕДАКТИРОВАТЬ: объяснение

Итак, (#)как вы определяете инфиксный оператор, я использую его просто как сокращение для mapприменения функции к каждому элементу списка. Устраняя этот и другой псевдоним l, избегая оператора 'direct-function-application' $и добавляя еще больше скобок и пробелов, и с реальными именами функций мы получаем:

oop string = map (verify (map (extract 0) knowledge)) (map (extract 1) questions)
 where (knowledge,questions) = break ((=='?').last.last) (map words (lines string))

extract n wordlist = (wordlist!!n,init (last wordlist))

verify knowledge (a,c) = (a==c)
               || or [verify knowledge (b,c) | b <- map snd (filter ((==a).fst) knowledge)]

map words (lines string) список списков слов каждой строки входной строки

(=='?').last.last является предикатом, указывающим, является ли последняя буква в последнем слове строки знаком вопроса, т.е. является ли строка вопросом.

break разбивает список в кортеже первой части без вопросов (все утверждения) и части из первого вопроса о (все вопросы).

mapping extract nдля этих элементов вынимает из каждого списка слов те элементы, которые нам действительно нужны, элемент nth (который в утверждениях является первым словом - так n == 0, а в вопросах - второе слово - так n == 1) с использованием !!оператора и последнего, из которого мы должны вырезать последнюю букву (или '.'или '?'), используя init.

(Обратите внимание, что я полностью игнорирую капитализацию, потому что я полностью игнорирую различие между классами и членами, члены - это просто листья дерева, построенного базой знаний (но не все листья представляют члены, они также могут быть классами без подклассов и членов ), в котором каждый дочерний узел представляет подкласс или член того, что представляет его родительский узел. Я ТОЛЬКО ПРИЗНАЛ, ЧТО ЭТО НЕПРАВИЛЬНО, ЧТО ДЕЛАТЬ В СЛУЧАЯХ, НЕ УКАЗАННЫХ OP. Скоро отредактирую решение.)

Теперь, map (extract 0) knowledgeи map (extract 1) questionsэто списки кортежей имен, представляющих подкласс или членское отношение первого ко второму.

Все кортежи in map (extract 0) knowledgeявляются истинными отношениями, map (extract 1) questionsтеперь они отображаются на verifyфункцию с первым аргументом, установленным в map (extract 0) knowledge.

(Отныне, внутри verify, knowledgeэто имя параметра и относится к уже extractотредактированному списку кортежей.)

(Кроме того, при чтении verifyобратите внимание, что хотя ||(после не элегантного разрыва строки, чтобы избежать горизонтальной прокрутки на SE) это нормальное логическое дизъюнкция между регистром «возвратный» и «рекурсивный», orсворачивает его в список, то есть проверяет, есть ли Элемент списка имеет значение true.)

Теперь отношения, очевидно, правильные, если они рефлексивные. Строго говоря, нет, potatoне имеетpotato (и это даже не в том смысле , «есть» используется здесь, как и в «A Cop является Cop»), но это только условие завершения , которое охватывает все отношения после ходить по дереву (что в отличие от настоящих деревьев означает «к листьям»).

Во всех других случаях мы пытаемся взять кортеж из knowledge(после того, как мы filterвыполнили его, чтобы убедиться, что мы «видим» только пары с тем же первым элементом, который мы хотим проверить), и продолжаем с того места, на которое он указывает. Понимание списка имеет дело со всеми возможными кортежами для продолжения и вызывает verifyснова в каждом случае. У тупика просто будет здесь пустой список, и он будет возвращен в falseцелом, и, следовательно, не повлияет на экземпляр, verifyкоторый был вызван.

Лейф Виллертс
источник
Не могли бы вы добавить краткое объяснение для людей, не владеющих хаскелем?
Дж Аткин
Счастливо! Я просто не делаю это для каждого поста, пока не будет запрошено.
Лейф Виллертс
Хорошо спасибо! (наполнитель)
J Аткин
Вау, это какое-то объяснение.
Дж Аткин
2
Я только что закончил читать первую половину, Learn you a haskell for great good!и теперь я это понимаю! (Этот ответ на самом деле побудил меня узнать больше о haskell и FP, и это оооочень круто!)
J Atkin
4

JavaScript, 265 263 байта

for(o={};i=prompt().split(/\W/);)a=i[0],b=i[1],d=i[2],b=="is"?((o[a]=o[a]||{p:[],k:{}}).p.push(d),o[d]=o[d]||{p:[],k:{}}):b=="has"?o[a].k[d]=1:alert(o[b]&&(a>"E"?b==d|(c=n=>~(p=o[n].p).indexOf(d)|p.some(c))(b):(c=n=>o[n].k.hasOwnProperty(i[4])|o[n].p.some(c))(b)))

Введите пустую строку, чтобы выйти.

объяснение

for(
  o={};                               // o = all objects
  i=prompt().split(/\W/);             // i = command as an array of words
)
  a=i[0],                             // a = first word
  b=i[1],                             // b = second word
  //c=i[2],                           // c = third word
  d=i[3],                             // b = fourth word
  //e=i[4],                           // e = fifth word

  // Case: <name> is a <name>.
  b=="is"?(
    (o[a]=o[a]||{p:[],k:{}})          // create the object if it does not exist
      .p.push(d),                     // add the parent to the object's list of parents
    o[d]=o[d]||{p:[],k:{}}            // create the parent if it does not exist
  ):

  // Case: <name> has a <name>.
  b=="has"?
    o[a].k[d]=1                       // set the specified property

  :
  alert(                              // display the responses to the questions
    o[b]                              // false if the queried object does not exist
    &&(

      // Case: Is <name> a <name>?
      a>"E"?                          // "Is" > "E" and "Does" < "E"
        b==d                          // check if it is itself
        |(c=n=>
          ~(p=o[n].p)                 // p = direct parents of current object
            .indexOf(d)               // check direct parents for the object
          |p.some(c)                  // check the grandparents
        )(b)

      // Case: Does <name> have a <name>?
      :
        (c=n=>
          o[n].k.hasOwnProperty(i[4]) // check if this object has the property
          |o[n].p.some(c)             // check it's parents for the property also
        )(b)
    )
  )
user81655
источник
Не могли бы вы использовать string.split(" ");?
Дж Аткин
@JAtkin Я использовал, .match(/\w+/g)чтобы убрать пунктуацию со слов.
user81655
Я видел это, но не .split(" ")будет короче, или я что-то упустил? (Я не знаю javascript)
Дж Аткин
@JAtkin Если бы я использовал, .splitя также должен был бы использовать .slice(0,-1)(дважды), потому B is a A.что сделал бы Bнаследование A..).
user81655 22.11.15
@JAtkin На самом деле я только что узнал, что split принимает регулярные выражения, чтобы я мог использовать .split(/\W/). Спасибо, что заставил меня посмотреть это!
user81655 22.11.15