Golf ich ein OOP!

26

Golf ich ein OOP!

Zwei wichtige Komponenten der objektorientierten Programmierung sind Vererbung und Komposition. Zusammen ermöglichen sie die Erstellung einfacher, aber leistungsfähiger Klassenhierarchien zur Lösung von Problemen. Ihre Aufgabe besteht darin, eine Reihe von Anweisungen zu einer Klassenhierarchie zu analysieren und Fragen zur Hierarchie zu beantworten.

Eingang

Eine Reihe von Anweisungen und Fragen zu einer Klassenhierarchie, die aus einer Datei oder Standardeingabe gelesen werden, je nachdem, was für Ihre Sprache am besten geeignet ist. Wenn Sie die Option file verwenden, wird der Dateiname als erstes Argument an Ihren Code übergeben (Funktionsargument oder Befehlszeilenargument, je nachdem, was Sie auswählen). Das Format ist wie folgt:

<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

Die Eingabe wird immer Aussagen, dann Fragen sein. Alle Klassennamen beginnen mit einem englischen Großbuchstaben ( A-Z) und alle Mitgliedsnamen mit einem englischen Kleinbuchstaben ( a-z). Bei allen Namen muss die Groß- und Kleinschreibung beachtet werden - entspricht ABC123nicht der Klasse von Abc123.

Es wird keine zyklische Vererbung geben - wenn Berbt von A, Awird er nicht von Boder von einem der BKinder erben .

Nur Klassennamen werden Teil einer Hierarchie - Anweisungen wie foo is a bar.oder document has a name.werden nicht vorkommen.

Ausgabe

Eine Reihe wahrer oder falscher Werte als Antworten auf die Abfragen, die in die Standardausgabe oder als Rückgabewert Ihrer Funktion geschrieben wurden. Wenn Sie nicht genügend Informationen haben, um eine Frage zu beantworten (z. B. Fragen, die Namen betreffen, die Sie in den Aussagen nicht gesehen haben), antworten Sie mit einem falschen Wert.

Testfälle

Fall 1:

Eingang:

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?

Ausgabe:

True
True
False

Fall 2:

Eingang:

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?

Ausgabe:

True
True
False
False
True

Regeln

  • Sie können mit einer Funktion oder einem Programm antworten
  • Standardlücken sind verboten
  • Das ist , also gewinnt die kürzeste richtige Antwort in Byte
  • Die Gewinnerantwort wird in einer Woche ausgewählt

Viel Glück und möge die OOP bei dir sein!

Bestenliste

Das Stapel-Snippet am Ende dieses Beitrags generiert die Rangliste aus den Antworten a) als Liste der kürzesten Lösungen pro Sprache und b) als Gesamtrangliste.

Um sicherzustellen, dass Ihre Antwort angezeigt wird, beginnen Sie Ihre Antwort mit einer Überschrift. Verwenden Sie dazu die folgende Markdown-Vorlage:

## Language Name, N bytes

Wo Nist die Größe Ihres Beitrags? Wenn Sie Ihren Score zu verbessern, Sie können alte Rechnungen in der Überschrift halten, indem man sich durch das Anschlagen. Zum Beispiel:

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

Wenn Sie mehrere Zahlen in Ihre Kopfzeile aufnehmen möchten (z. B. weil Ihre Punktzahl die Summe von zwei Dateien ist oder wenn Sie die Strafen für Interpreter-Flags separat auflisten möchten), stellen Sie sicher, dass die tatsächliche Punktzahl die letzte Zahl in der Kopfzeile ist:

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

Sie können den Namen der Sprache auch als Link festlegen, der dann im Snippet angezeigt wird:

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

Mego
quelle
Wie ist Does Criminal have a name?gleich True? Haben alle Objekte einen Namen?
J Atkin
4
@JAtkin Criminal is a Person. Person has a name.
Reto Koradi
Ahh ... das hatte ich verpasst.
J Atkin
Muss ich alle Eingaben auf einmal erfassen oder kann ich sie wie eine interaktive Konsole zeilenweise erfassen? Wenn # 2, kann ich eine truey \ falsey ausgeben, auch wenn die Eingabe eine Anweisung ist?
J Atkin
@JAtkin Alles auf einmal oder Zeile für Zeile nach Ihrer Wahl. Wenn es eine Aussage ist, sollte es keine Ausgabe geben. Nur Fragen bekommen Antworten.
Mego

Antworten:

13

CJam, 59 Bytes

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

Dies endet sofort für beide Testfälle.

Es gibt entweder den zweiten Vornamen der Frage oder 1(beide wahr) oder 0(falsch) aus.

Probieren Sie es online im CJam-Interpreter aus .

Idee

Aufgrund der Unterscheidung zwischen Klassen und Mitgliedern besteht die Herausforderung darin, eine Vorbestellung zu erstellen, für die die Eingabe eine Teildefinition liefert.

Wir definieren, dass xy wenn x ein y ist oder x ein y hat .

Für den ersten Testfall lautet der Eingang BA , CB und Afoo . Wegen der Transitivität, haben wir auch Bfoo , CA und Afoo . Wegen der Reflexivität ist xx immer wahr.

Für eine gegebene Eingabe können wir daher die Teildefinition von ≺ aus den Aussagen extrahieren, die Transitivität ausreichend oft anwenden, um die Definition von ≺ zu vervollständigen und schließlich die Fragen zu beantworten.

Code

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
quelle
2
Dies ist beeindruckend, wenn man bedenkt, dass CJam keine Klassen hat: D
Beta Decay
Das ist schön.
Mego
@BetaDecay-Klassen sind im Wesentlichen verschachtelte Mengen. Klassen sind in jeder Sprache implementiert. Sagen Sie im ersten Beispiel. C:{B:{A:{foo:{}}}}
A
8

Python 3, 431 331 308 Bytes

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)

Dies ist die Vollversion mit Kommentaren

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)

Ausgabe für Testfall 1:

True
True
False

Fall 2:

True
True
False
False
True

Ich habe die Debug-Befehle aus Gründen der Übersichtlichkeit im Hauptprogramm entfernt, aber wenn Sie sie sehen möchten, schauen Sie einfach in den Verlauf

J Atkin
quelle
Anstatt global fin zu verwenden h(z), verwenden def h(z,f)und übergeben Sie das globale fin, wenn Sie es aufrufen. Tatsächlich brauchen Sie das gar nicht h(z)- platzieren Sie den Körper einfach dort, wo Sie ihn nennen. Sie müssen nicht r=2und können auch einfach auf das print(r)verzichten if, da Sie für falsche Abfragen einen Falsey-Wert ausgeben müssen. Sie können umbenannt , synum zdort und abrasieren mehr Bytes. Ich glaube nicht, dass du das []um dein Listenverständnis im ersten brauchst any.
Mego
Sie verwenden auch eeinmal, damit Sie die Definition aufheben und einfach verwenden können [a,b,c,d]. Statt if s(i,g) is not Nonetun if s(i,g)- re.MatchObjekte werden immer ausgewertet , Truewenn eine Übereinstimmung gefunden wird. Sie können auch 2 Bytes mit löschen f[x]+=f[y].
Mego
@Mego Wow, danke für alle Tipps. Ich muss sie später einfügen.
J Atkin
Dieser Beitrag wird dir wahrscheinlich sehr helfen
Mego
@Mego Vielen Dank, jetzt sind es 396. Ich werde in Kürze posten.
J Atkin
4

Haskell, 157 Bytes

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

Gib die Zeichenfolge an o. Nicht sicher, ob das Erstellen xund v('extrahieren' und 'überprüfen') von Infixen mehr schneidet als das Erstellen mapeines Infixes, oder ob beides möglich ist.

EDIT: Erklärung

So (#)wie Sie einen Infix-Operator definieren, verwende ich ihn nur als Kurzform für das mapAnwenden einer Funktion auf jedes Element einer Liste. Lösen Sie diesen und den anderen Alias l, vermeiden Sie den Operator 'direct-function-application' $und fügen Sie noch mehr Klammern und Abstände hinzu. Mit echten Funktionsnamen erhalten Sie:

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) ist eine Liste der Wortlisten der einzelnen Zeilen in der Eingabezeichenfolge.

(=='?').last.last ist ein Prädikat, das angibt, ob der letzte Buchstabe im letzten Wort einer Zeile ein Fragezeichen ist, dh ob die Zeile eine Frage ist.

break Bricht die Liste in ein Tupel des ersten Teils ohne Fragen (alle Aussagen) und des Teils ab der ersten Frage (alle Fragen).

mapping extract nauf diese nimmt aus jeder Wortliste die Elemente heraus, die wir wirklich wollen, das nth (das in Aussagen das erste Wort ist - also n == 0, und in Fragen das zweite Wort - also n == 1) unter Verwendung des !!Operators und des letzten, von dem wir muss den letzten Buchstaben (entweder '.'oder '?') mit schneiden init.

(Beachten Sie, dass ich die Groß- und Kleinschreibung völlig ignoriere, da ich die Unterscheidung zwischen Klassen und Mitgliedern völlig ignoriere. Mitglieder sind nur Blätter eines von der Wissensbasis erstellten Baums (aber nicht alle Blätter repräsentieren Mitglieder, sie können auch Klassen ohne Unterklassen oder Mitglieder sein.) ), wobei jeder untergeordnete Knoten eine Unterklasse oder ein Mitglied dessen darstellt, was sein übergeordneter Knoten darstellt. ICH HABE NUR FALLE FALLE FALLE FALLE FALLE FALLE FALLE FALLE FALLE FALLE FALLE FALLE FALLE

Nun, map (extract 0) knowledgeund map (extract 1) questionssind Listen von Tupeln von Namen, die eine Unterklassen- oder Mitgliedsbeziehung von der ersten zur zweiten darstellen.

Die Tupel in map (extract 0) knowledgesind alles wahre Beziehungen, die in map (extract 1) questionssind nun der verifyFunktion zugeordnet, wobei das erste Argument auf gesetzt ist map (extract 0) knowledge.

(Von nun an nach innen verify, knowledgeist ein Parametername und bezieht sich auf die bereits extracted Tupel - Liste.)

( verifyBeachten Sie beim Lesen auch , dass, während das ||(nach dem uneleganten Zeilenumbruch, um horizontales Scrollen auf SE zu vermeiden) eine normale boolesche Disjunktion zwischen dem 'reflexiven' und dem 'rekursiven' Fall ist, ordas über eine Liste faltet, dh prüft, ob es eine gibt Listenelement ist wahr.)

Nun ist eine Beziehung offensichtlich richtig, wenn sie reflexiv ist. Streng genommen, nein, ein potatonicht funktioniert hat eine potato(und es ist nicht einmal ein in dem Sinne ‚ist‘ wird hier verwendet, wie in ‚A Cop ist ein Cop‘), aber das ist nur die Abbruchbedingung , dass deckt alle Beziehungen nach den Baum hinuntergehen (was anders als bei echten Bäumen "auf die Blätter zugehen" bedeutet).

In allen anderen Fällen versuchen wir, ein Tupel von knowledge(nachdem wir filtersichergestellt haben, dass wir nur Paare mit demselben ersten Element sehen, das wir überprüfen möchten) zu nehmen und von dort aus fortzufahren, wo es hinweist. Das Listenverständnis behandelt alle möglichen Tupel, um fortzufahren und ruft jeweils verifywieder auf. Eine Sackgasse hat hier nur eine leere Liste und kehrt falseinsgesamt zurück. Sie hat also keinen Einfluss auf die Instanz, von der verifysie aufgerufen wurde.

Leif Willerts
quelle
Könnten Sie eine kurze Erklärung für Leute hinzufügen, die nicht fließend sind?
J Atkin
Glücklich! Ich mache es einfach nicht für jeden Beitrag, bis ich dazu aufgefordert werde.
Leif Willerts
OK danke! (Füller)
J Atkin
Wow, das ist eine Erklärung.
J Atkin
2
Ich habe gerade die erste Hälfte von gelesen Learn you a haskell for great good!und jetzt verstehe ich das! (Diese Antwort hat mich dazu veranlasst, mehr über Haskell und FP zu erfahren, und es ist sooooo cool!)
J Atkin
4

JavaScript, 265 263 Bytes

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

Geben Sie eine leere Zeichenfolge ein, um den Vorgang zu beenden.

Erläuterung

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
quelle
Könnten Sie verwenden string.split(" ");?
J Atkin
@JAtkin Ich habe .match(/\w+/g)die Interpunktion aus den Wörtern entfernt.
user81655
Ich habe das gesehen, würde aber .split(" ")nicht kürzer sein oder vermisse ich etwas? (Ich weiß nicht, Javascript)
J Atkin
@JAtkin Wenn ich das benutzt .splithätte müsste ich das auch .slice(0,-1)(zweimal) machen, weil das (mit dem ) erben B is a A.würde . BA..
user81655
@JAtkin Eigentlich habe ich gerade herausgefunden, dass split reguläre Ausdrücke akzeptiert, damit ich sie verwenden kann .split(/\W/). Danke, dass ich das nachschlagen musste!
user81655