Гольф мене ООП!


26

Гольф мене ООП!

Дві важливі складові об'єктно-орієнтованого програмування - спадкування та склад. Разом вони дозволяють створити прості, але потужні ієрархії класів для вирішення проблем. Ваше завдання - проаналізувати ряд висловлювань про ієрархію класів та відповісти на запитання про ієрархію.

Вхідні дані

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

<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

Правила

  • Ви можете відповісти за допомогою функції або програми
  • Стандартні лазівки заборонені
  • Це , тому найкоротша правильна відповідь у байтах виграє
  • Виграшну відповідь буде обрано через один тиждень

Удачі, і нехай ООП буде з вами!

Таблиця лідерів

Фрагмент стека внизу цієї публікації генерує таблицю лідерів з відповідей а) як список найкоротших варіантів для кожної мови та б) як загальну таблицю лідерів.

Щоб переконатися, що ваша відповідь відображається, будь ласка, почніть свою відповідь із заголовка, використовуючи наступний шаблон Markdown:

## 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


Як Does Criminal have a name?дорівнює True? Чи всі об’єкти мають ім’я?
Дж. Аткін

4
@JAtkin Criminal is a Person. Person has a name.
Рето Кораді

А-а ... я це пропустив.
J Atkin

Чи потрібно брати весь вхід одразу чи я можу приймати його по черзі, як інтерактивна консоль? Якщо №2, чи можу я вивести ковтун \ фальси, навіть якщо вхід є статусом?
J Atkin

@JAtkin Все відразу або по черзі, на ваш вибір. Якщо це твердження, не повинно бути жодного результату. Лише запитання отримують відповіді.
Мего

Відповіді:


13

CJam, 59 байт

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

Це закінчується миттєво для обох тестових випадків.

Він або друкує ім'я другого імені питання, або 1(обидва), або 0(помилково).

Спробуйте його в Інтернеті в інтерпретаторі CJam .

Ідея

Через різницю між класами та членами, виклик зводиться до створення попереднього замовлення, для якого вхід дає часткове визначення.

Визначимо, що xy iff x є y або x має y .

Для першого тестового випадку вхід вказує, що BA , CB і Afoo . Через транзитивності ми також маємо Bfoo , CA і Afoo . Крім того , з - за рефлексивності, хх завжди вірно.

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

Код

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 fв h(z), використанні def h(z,f)і передати глобальний fв при виклику його. Насправді вам це зовсім не потрібно h(z)- просто покладіть тіло, куди ви його називаєте. Вам не потрібно r=2, і ви можете просто обійтися print(r)без if, оскільки вам потрібно вивести значення фальси для помилкових запитів. Ви можете перейменовувати synна нього zта відголити кілька байтів. Я не думаю, що вам потрібно []спочатку розуміти список any.
Мего

Ви також використовуєте eодин раз, так що ви можете піти з визначення та просто використовувати [a,b,c,d]. Замість того if s(i,g) is not None, щоб if s(i,g)- re.Matchоб’єкти завжди оцінюються, Trueякщо знайдено відповідність. Ви також можете скинути 2 байти за допомогою f[x]+=f[y].
Мего

@ Mee Wow, дякую за всі поради. Мені потрібно буде подати їх згодом.
Дж. Аткін

Цей пост , ймовірно, вам дуже допоможе
Mego

@ Mee Велике спасибі, його знизилося до 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('вилучення' та 'перевірка') інфіксів скорочує більше, ніж створення mapінфіксації, або якщо можливе те й інше.

EDIT: Пояснення

Отже, (#)як ви визначаєте оператора infix, я використовую його як скорочення 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по цим виймає з кожного списку слів потрібні нам елементи, той n(який у висловлюваннях - це перше слово - так n == 0, а в питаннях - друге слово - так n == 1), використовуючи !!оператор і останнє, з якого ми повинні вирізати останню букву (або '.'або '?'), використовуючи init.

(Зауважте, що я повністю ігнорую великі літери, це тому, що я повністю ігнорую різницю між класами та членами, члени - це просто листя дерева, побудовані на базі знань (але не всі листя представляють членів, вони також можуть бути класами, що не мають підкласів і членів ), у якому кожен дочірній вузол являє собою підклас або член того, що представляє його батьківський вузол. Я ПЕРЕБІРУВАННЯ ЦЬОГО НЕБЕЗПЕЧНО, ЩО РОБИТИ у випадках, не охоплених ОП. Відредагуйте рішення незабаром.)

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

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

(З цього моменту, всередині verify, knowledgeце ім'я параметра і відноситься до вже extractéd список кортежів.)

(Також, читаючи verify, зауважте, що в той час, як ||(після неелегантного розриву рядків, щоб уникнути горизонтального прокручування на SE), це нормальна булева диз'юнкція між "рефлексивним" та "рекурсивним" випадком, orскладе це за списком, тобто перевіряє, чи є Елемент списку істинний.)

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

У всіх інших випадках ми намагаємось взяти кортеж knowledge(після того, як ми filterпереконаємось, що ми «бачимо» лише пари з тим самим першим елементом, що і ми хочемо перевірити), і рухаємось далі, куди вказує. Розуміння списку стосується всіх можливих кортежів для продовження та закликає verifyзнову у кожному конкретному випадку. Тут буде просто порожній список і повернеться falseзагалом, і не впливатиме на його екземпляр verify.


Не могли б ви додати коротке пояснення людям, що не мають вільних знань
J Atkin

Щасливо! Я просто не роблю це для кожної публікації, поки не вимагають.
Лейф Віллерц

Добре, дякую! (наповнювач)
J Atkin

Ого, це якесь пояснення.
J Atkin

2
Я щойно закінчив читати першу половину, Learn you a haskell for great good!і це зараз я розумію! (Ця відповідь насправді те, що спонукало мене дізнатися більше про haskell та FP, і це sooooo круто!)
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)
    )
  )

Чи можете ви скористатися string.split(" ");?
J Atkin

@JAtkin Я використовував .match(/\w+/g)для видалення пунктуації зі слів.
користувач81655

Я бачив це, але не .split(" ")було б коротшим чи я щось пропускаю? (Я не знаю javascript)
J Atkin

@JAtkin Якби я використовував, .splitя також повинен був би скористатися .slice(0,-1)(двічі), тому щоB is a A. що зробив би Bспадщину A..).
користувач81655

@JAtkin Насправді я лише з'ясував, що розкол приймає регулярні вирази, щоб я міг використовувати .split(/\W/). Дякуємо, що змусили мене подивитися на це!
користувач81655
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.