Golf Me OOP!

26

Golf Me OOP!

Dwa ważne elementy programowania obiektowego to dziedziczenie i kompozycja. Razem pozwalają na tworzenie prostych, ale potężnych hierarchii klas w celu rozwiązywania problemów. Twoim zadaniem jest przeanalizowanie szeregu stwierdzeń dotyczących hierarchii klas i udzielenie odpowiedzi na pytania dotyczące hierarchii.

Wkład

Seria stwierdzeń i pytań dotyczących hierarchii klas, czytanych z pliku lub standardowego wejścia, w zależności od tego, który język jest najlepszy. Jeśli użyjesz opcji pliku, nazwa pliku zostanie przekazana jako pierwszy argument do Twojego kodu (argument funkcji lub argument wiersza poleceń, zależnie od tego, co wybierzesz). Format jest następujący:

<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

Wkładem będą zawsze stwierdzenia, a następnie pytania. Wszystkie nazwy klas A-Zzaczynają się od dużej litery angielskiej ( ), a wszystkie nazwy członków zaczynają się od małej litery angielskiej ( a-z). W nazwach rozróżniana ABC123jest wielkość liter - nie jest to ta sama klasa, co Abc123.

Nie będzie żadnego cyklicznego dziedziczenia - jeśli Bodziedziczy po nim A, Anie odziedziczy po nim Bani żadnym z Bjego dzieci.

Tylko nazwy klas będą stanowić część hierarchii - instrukcje takie jak foo is a bar.lub document has a name.nie będą występować.

Wydajność

Szereg prawdziwych lub falsey wartości, jako odpowiedzi na zapytania zapisane na standardowym wyjściu lub jako wartość zwracana przez twoją funkcję. Jeśli nie masz wystarczających informacji, aby odpowiedzieć na pytanie (np. Pytania dotyczące nazwisk, których nie widziałeś w wypowiedziach), odpowiedz z wartością falsey.

Przypadki testowe

Przypadek 1:

Wkład:

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?

Wydajność:

True
True
False

Przypadek 2:

Wkład:

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?

Wydajność:

True
True
False
False
True

Zasady

  • Możesz odpowiedzieć za pomocą funkcji lub programu
  • Standardowe luki są zabronione
  • To jest , więc wygrywa najkrótsza poprawna odpowiedź w bajtach
  • Zwycięska odpowiedź zostanie wybrana za tydzień

Powodzenia i niech OOP będzie z tobą!

Tabela liderów

Fragment kodu na dole tego postu generuje tabelę wyników na podstawie odpowiedzi a) jako lista najkrótszych rozwiązań dla każdego języka oraz b) jako ogólna tabela wyników.

Aby upewnić się, że Twoja odpowiedź się pojawi, zacznij od nagłówka, korzystając z następującego szablonu Markdown:

## Language Name, N bytes

gdzie Njest rozmiar twojego zgłoszenia. Jeśli poprawić swój wynik, to może zachować stare porachunki w nagłówku, uderzając je przez. Na przykład:

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

Jeśli chcesz umieścić w nagłówku wiele liczb (np. Ponieważ twój wynik jest sumą dwóch plików lub chcesz osobno wymienić kary za flagi tłumacza), upewnij się, że rzeczywisty wynik jest ostatnią liczbą w nagłówku:

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

Możesz także ustawić nazwę języka jako link, który pojawi się we fragmencie:

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

Mego
źródło
Jak to jest Does Criminal have a name?równe True? Czy wszystkie obiekty mają nazwę?
J Atkin
4
@JAtkin Criminal is a Person. Person has a name.
Reto Koradi
Ahh ... tęskniłem za tym.
J Atkin,
Czy muszę pobierać wszystkie dane naraz, czy też mogę pobierać je wiersz po wierszu, jak konsola interaktywna? Jeśli # 2, czy mogę wypisać prawdę \ falsey, nawet jeśli dane wejściowe to zestawienie?
J Atkin,
@JAtkin Wszystko na raz lub linia po linii, twój wybór. Jeśli jest to stwierdzenie, nie powinno być żadnych wyników. Tylko pytania otrzymują odpowiedzi.
Mego,

Odpowiedzi:

13

CJam, 59 bajtów

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

To kończy się natychmiast dla obu przypadków testowych.

Drukuje albo drugie imię pytania, albo 1(oba prawdziwe) lub 0(falsy).

Wypróbuj online w interpretatorze CJam .

Pomysł

Z powodu rozróżnienia między klasami i członkami wyzwanie sprowadza się do stworzenia przedsprzedaż, dla którego dane wejściowe zapewniają częściową definicję.

Definiujemy, że xy iff x jest y lub x ma y .

W pierwszym przypadku testowym dane wejściowe stwierdzają, że BA , CB i Afoo . Z powodu przechodniości mamy również Bfoo , CA i Afoo . Ponadto, ze względu na zwrotność, xx jest zawsze prawdziwe.

Dla danego wkładu możemy zatem wyodrębnić częściową definicję ≺ ze zdań, zastosować przechodniość wystarczającą ilość razy, aby ukończyć definicję ≺ i ostatecznie odpowiedzieć na pytania.

Kod

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#
Dennis
źródło
2
To imponujące, biorąc pod uwagę, że CJam nie ma zajęć: D
Beta Decay
To jest piękne.
Mego,
@BetaDecay Klasy są zasadniczo zestawami zagnieżdżonymi; zajęcia są realizowane w każdym języku. Powiedz w pierwszym przykładzie. C:{B:{A:{foo:{}}}}
A̲̲
8

Python 3, 431 331 308 bajtów

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)

To jest pełna wersja z komentarzami

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)

Dane wyjściowe dla przypadku testowego nr 1:

True
True
False

Przypadek nr 2:

True
True
False
False
True

Usunąłem polecenia debugowania dla przejrzystości w głównym programie, ale jeśli chcesz je zobaczyć, po prostu zajrzyj do historii

J Atkin
źródło
Zamiast używać global fin h(z), używaj def h(z,f)i przekazuj globalny fpodczas wywoływania go. W rzeczywistości nie potrzebujesz h(z)wcale - po prostu umieść ciało tak, jak to nazywasz. Nie potrzebujesz r=2i możesz po prostu obejść się print(r)bez if, ponieważ musisz podać wartość falsey dla fałszywych zapytań. Można zmienić nazwę syn, aby zi ogolił tam kilka bajtów. Nie sądzę, żebyś najpierw potrzebował []zrozumienia całej listy any.
Mego,
Używasz także eraz, więc możesz zrezygnować z definicji i po prostu użyć [a,b,c,d]. Zamiast if s(i,g) is not None, zrobić if s(i,g)- re.Matchobiekty są zawsze ocenia się True, jeśli zostanie znaleziony. Możesz także upuścić 2 bajty za pomocą f[x]+=f[y].
Mego,
@Mego Wow, dzięki za wszystkie wskazówki. Będę musiał je później wprowadzić.
J Atkin,
Ten post prawdopodobnie ci bardzo pomoże
Mego,
@Mego Wielkie dzięki, teraz do 396. Wkrótce opublikuję.
J Atkin,
4

Haskell, 157 bajtów

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

Daj ciąg do o. Nie jestem pewien, czy tworzenie xi v(wyodrębnianie i weryfikowanie) poprawek tnie więcej niż tworzenie mappoprawek, czy też oba są możliwe.

EDYCJA: Objaśnienie

Tak (#)definiuje się operator infix, używam go jedynie jako skrótu dla mapzastosowania funkcji do każdego elementu listy. Rozwiązując ten i inny alias l, unikając operatora „funkcji bezpośredniej aplikacji” $i dodając jeszcze więcej nawiasów i odstępów między nimi, a przy rzeczywistych nazwach funkcji dochodzimy do:

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) to lista list słów każdego wiersza w ciągu wejściowym.

(=='?').last.last jest predykatem wskazującym, czy ostatnia litera w ostatnim słowie linii jest znakiem zapytania, tj. czy linia jest pytaniem.

break łamie listę w krotce pierwszej części bez pytań (wszystkie wypowiedzi) i części z pierwszego pytania na (wszystkie pytania).

mappingowanie extract nna nich usuwa z każdej listy słów elementy, których naprawdę chcemy, ten njeden (który w instrukcjach jest pierwszym słowem - więc n == 0, a w pytaniach jest drugim słowem - więc n == 1) za pomocą !!operatora i ostatni, z którego muszę wyciąć ostatnią literę (albo '.'albo '?') używając init.

(Zauważ, że całkowicie ignoruję wielkie litery, ponieważ całkowicie ignoruję rozróżnienie między klasami i elementami, członkowie są tylko liśćmi drzewa zbudowanymi przez bazę wiedzy (ale nie wszystkie liście reprezentują członków, mogą być również klasami bez podklas ani członków) ), w którym każdy węzeł podrzędny reprezentuje podklasę lub element tego, co reprezentuje jego węzeł nadrzędny. PO PROSTU ZREALIZOWAŁEM TO NIEWŁAŚCIWE DO ZROBIENIA w przypadkach nieobjętych OP. Wkrótce dokonam edycji rozwiązania.)

Teraz map (extract 0) knowledgei map (extract 1) questionsto listy krotek nazwisk reprezentujących subclass- lub państwa-relację między pierwszym a drugim.

Krotki w map (extract 0) knowledgesą prawdziwymi relacjami, te w map (extract 1) questionssą teraz zamapowane na verifyfunkcję, z pierwszym argumentem ustawionym na map (extract 0) knowledge.

(Od teraz, w środku verify, knowledgeto nazwa parametru i odnosi się do już extractlisty krotki ed.)

(Podczas czytania verifynależy również zauważyć, że chociaż ||(po nieeleganckim łamaniu wiersza, aby uniknąć przewijania w poziomie w SE) jest normalnym rozróżnieniem boolowskim między przypadkiem „refleksyjnym” a „rekurencyjnym”, orskłada to na liście, tzn. Sprawdza, czy jakieś element listy jest prawdziwy).

Teraz relacje są oczywiście poprawne, jeśli są zwrotne. Ściśle mówiąc, nie, potatonie mająpotato (i to nie jest jeszcze jeden w tym sensie „jest” jest używany tutaj, podobnie jak w „gliną jest Cop”), ale to tylko warunek zakończenia, które obejmuje wszystkie związki po schodzenie po drzewie (co w przeciwieństwie do prawdziwych drzew oznacza „w kierunku liści”).

We wszystkich innych przypadkach próbujemy pobrać krotkę knowledge(po tym, jak filterupewnimy się, że „widzimy” tylko pary z tym samym pierwszym elementem, który chcemy sprawdzić), i kontynuujemy od miejsca, w którym wskazuje. Zrozumienie listy dotyczy wszystkich możliwych krotek, aby kontynuować i verifyw każdym przypadku ponownie wywołuje . Ślepy zaułek będzie po prostu miał pustą listę i zwróci falseogólnie, więc nie wpłynie to na verifyjej wywołanie.

Leif Willerts
źródło
Czy mógłbyś dodać krótkie wyjaśnienie dla osób, które nie posługują się haskellem?
J Atkin,
Szczęśliwie! Po prostu nie robię tego dla każdego postu, dopóki nie zostanie o to poproszony.
Leif Willerts
Ok dzięki! (wypełniający)
J Atkin
Wow, to jakieś wytłumaczenie.
J Atkin,
2
Właśnie skończyłem czytać pierwszą połowę Learn you a haskell for great good!i teraz to rozumiem! (Ta odpowiedź właściwie skłoniła mnie do dowiedzenia się więcej o haskell i FP, i to jest takie fajne!)
J Atkin
4

JavaScript, 265 263 bajtów

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

Wpisz pusty ciąg, aby wyjść.

Wyjaśnienie

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)
    )
  )
użytkownik 81655
źródło
Można użyć string.split(" ");?
J Atkin,
@JAtkin Usuwałem .match(/\w+/g)znaki interpunkcyjne ze słów.
user81655,
Widziałem to, ale czy nie .split(" ")byłoby krótsze, czy coś mi umknęło? (Nie znam javascript)
J Atkin
@JAtkin Jeśli kiedyś .splitbędę mieć również do użytku .slice(0,-1)(dwa razy), ponieważ B is a A.uczyniłoby Bdziedziczą A.(z .).
user81655,
@JAtkin Właściwie właśnie dowiedziałem się, że split akceptuje wyrażenia regularne, więc mogę ich użyć .split(/\W/). Dzięki, że kazałeś mi to sprawdzić!
user81655,