Golf Me An OOP!


26

Golf Me An OOP!

Due componenti importanti della programmazione orientata agli oggetti sono ereditarietà e composizione. Insieme, consentono di creare gerarchie di classi semplici ma potenti per risolvere i problemi. Il tuo compito è analizzare una serie di dichiarazioni su una gerarchia di classi e rispondere a domande sulla gerarchia.

Ingresso

Una serie di dichiarazioni e domande su una gerarchia di classi, lette da un file o da un input standard, a seconda di quale sia la migliore per la tua lingua. Se si utilizza l'opzione file, il nome file verrà passato come primo argomento al codice (argomento della funzione o argomento della riga di comando, a seconda di quale si sceglie). Il formato è il seguente:

<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

L'input sarà sempre dichiarazioni, quindi domande. Tutti i nomi delle classi inizieranno con una lettera inglese maiuscola ( A-Z) e tutti i nomi dei membri inizieranno con una lettera inglese minuscola ( a-z). Tutti i nomi fanno distinzione tra maiuscole e minuscole - ABC123non è la stessa classe di Abc123.

Non ci sarà alcuna eredità ciclica - se Beredita da A, Anon erediterà da Bo di alcun Bfiglio.

Solo i nomi delle classi faranno parte di una gerarchia, ad esempio istruzioni come foo is a bar. o document has a name.non si verificheranno.

Produzione

Una serie di valori di verità o falsità, come risposte alle query, scritti nell'output standard o come valore di ritorno della funzione. Se non si dispone di informazioni sufficienti per rispondere a una domanda (ad esempio domande che coinvolgono nomi che non sono stati visualizzati nelle dichiarazioni), rispondere con un valore falso.

Casi test

Caso 1:

Ingresso:

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?

Produzione:

True
True
False

Caso 2:

Ingresso:

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?

Produzione:

True
True
False
False
True

Regole

  • Puoi rispondere con una funzione o un programma
  • Sono vietate le scappatoie standard
  • Questo è , quindi vince la risposta corretta più breve in byte
  • La risposta vincente verrà scelta tra una settimana

Buona fortuna e che OOP sia con te!

Classifica

Lo snippet di stack in fondo a questo post genera la classifica dalle risposte a) come un elenco della soluzione più breve per lingua eb) come classifica generale.

Per assicurarti che la tua risposta venga visualizzata, ti preghiamo di iniziare la risposta con un titolo, utilizzando il seguente modello Markdown:

## Language Name, N bytes

dov'è Nla dimensione del tuo invio. Se si migliora il punteggio, è possibile mantenere i vecchi punteggi nel titolo, colpendoli. Per esempio:

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

Se si desidera includere più numeri nell'intestazione (ad es. Perché il punteggio è la somma di due file o si desidera elencare separatamente le penalità del flag dell'interprete), assicurarsi che il punteggio effettivo sia l' ultimo numero nell'intestazione:

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

Puoi anche rendere il nome della lingua un collegamento che verrà quindi visualizzato nello snippet:

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


Quanto è Does Criminal have a name?uguale a True? Tutti gli oggetti hanno un nome?
J Atkin,

4
@JAtkin Criminal is a Person. Person has a name.
Reto Koradi,

Ahh ... mi ero perso.
J Atkin,

Devo prendere tutti gli input in una volta o posso prenderli riga per riga come una console interattiva? Se n. 2, posso generare un valore di verità \ falso anche se l'input è una dichiarazione?
J Atkin,

@JAtkin Tutto in una volta o riga per riga, a tua scelta. Se è un'affermazione, non dovrebbe esserci alcun output. Solo le domande ottengono risposte.
Mego,

Risposte:


13

CJam, 59 byte

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

Questo termina immediatamente per entrambi i casi di test.

1Stampa il secondo nome della domanda o (entrambi sinceri), oppure0 (falsa).

Provalo online nell'interprete CJam .

Idea

A causa della distinzione tra classi e membri, la sfida si riduce alla creazione di un preordine per il quale l'input fornisce una definizione parziale.

Definiamo che xy iff x è un y o x ha un y .

Per il primo caso di test, l'ingresso indica che BA , CB e Apippo . A causa della transitività, abbiamo anche Bfoo , CA e Afoo . Inoltre, a causa della riflessività, xx è sempre vero.

Per un dato input, possiamo quindi estrarre la definizione parziale di ≺ dalle dichiarazioni, applicare la transitività un numero di volte sufficiente per completare la definizione di ≺ e infine rispondere alle domande.

Codice

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
Questo è impressionante considerando che CJam non ha classi: D
Beta Decay

Questo è bellissimo.
Mego,

Le classi @BetaDecay sono essenzialmente insiemi nidificati; le lezioni sono implementate in ogni lingua. Dì nel primo esempio. C:{B:{A:{foo:{}}}}
A̲̲

8

Python 3, 431 331 308 byte

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)

Questa è la versione completa con commenti

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)

Uscita per test case n. 1:

True
True
False

Caso n. 2:

True
True
False
False
True

Ho rimosso i comandi di debug per chiarezza nel programma principale, ma se vuoi vederli basta guardare nella cronologia


Invece di usare global fin h(z), usa def h(z,f)e passa il globale fquando lo chiami. In realtà, non è necessario h(z), basta posizionare il corpo nel modo in cui lo si chiama. Non è necessario r=2e puoi semplicemente fare a print(r)meno di if, poiché devi generare un valore false per query false. È possibile rinominare synper ze radersi diversi byte lì. Non penso che tu abbia bisogno della []comprensione intorno alla tua lista nel primo any.
Mego,

Usi anche euna volta, quindi puoi eliminare la definizione e semplicemente usare [a,b,c,d]. Invece di if s(i,g) is not None, do if s(i,g)- gli re.Matchoggetti vengono sempre valutati Truese viene trovata una corrispondenza. Puoi anche rilasciare 2 byte con f[x]+=f[y].
Mego,

@Mego Wow, grazie per tutti i suggerimenti. Dovrò inserirli più tardi.
J Atkin,

Questo post probabilmente ti aiuterà molto
Mego

@Mego Grazie mille, ora è sceso a 396. Pubblicherò a breve.
J Atkin,

4

Haskell, 157 byte

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

Dai la stringa a o. Non sono sicuro se effettuare xe v("estrarre" e "verificare") le correzioni siano più che apportare mapuna correzione, o se entrambi sono possibili.

EDIT: spiegazione

Quindi, (#)è come si definisce un operatore infix, lo uso solo come scorciatoia per mapapplicare una funzione a ciascun elemento di un elenco. Risolvendo questo e l'altro alias l, evitando l'operatore 'applicazione-funzione-diretta' $e aggiungendo ancora più parentesi e spaziando le cose, e con nomi di funzioni reali arriviamo a:

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) è un elenco di elenchi di parole di ciascuna riga nella stringa di input.

(=='?').last.last è un predicato che indica se l'ultima lettera nell'ultima parola di una riga è un punto interrogativo, ovvero se la riga è una domanda.

break rompe l'elenco in una tupla della prima parte senza domande (tutte le dichiarazioni) e la parte della prima domanda in (tutte le domande).

mapil ping extract nsu questi elimina da ogni elenco di parole gli elementi che vogliamo veramente, quello nth (che nelle istruzioni è la prima parola - così n == 0, e nelle domande è la seconda parola - quindi n == 1) usando l' !!operatore e l'ultimo, da cui noi tagliare l'ultima lettera (o '.'o '?') usando init.

(Nota che ignoro completamente la maiuscola, perché ignoro completamente la distinzione tra classi e membri, i membri sono solo foglie di un albero costruito dalla base di conoscenza (ma non tutte le foglie rappresentano membri, possono anche essere classi senza sottoclassi né membri ), in cui ogni nodo figlio rappresenta una sottoclasse o un membro di ciò che rappresenta il suo nodo padre. HO SOLO REALIZZATO QUESTA È UNA COSA SBAGLIATA da fare nei casi non coperti da OP. Presto modificherà la soluzione.)

Ora, map (extract 0) knowledgee map (extract 1) questionssono elenchi di tuple di nomi che rappresentano una sottoclasse o relazione del membro dal primo al secondo.

Le tuple in map (extract 0) knowledgesono tutte vere relazioni, quelle in map (extract 1) questionssono ora mappate verifysopra la funzione, con il primo argomento impostato su map (extract 0) knowledge.

(D'ora in poi, dentro verify, knowledgec'è un nome di parametro e si riferisce extractall'elenco di tuple già modificato .)

(Inoltre, durante la lettura verify, si noti che mentre il ||(dopo l'interruzione di riga inelegante per evitare lo scorrimento orizzontale su SE) è una normale disgiunzione booleana tra il caso 'riflessivo' e il caso 'ricorsivo', lo orpiega su un elenco, cioè controlla se ci sono elemento list è vero.)

Ora, una relazione è ovviamente corretta se è riflessiva. A rigor di termini, no, a potatonon ha un potato(e non è nemmeno uno nel senso che 'is' viene usato qui, come in 'A Cop is a Cop'), ma questa è solo la condizione di terminazione che copre tutte le relazioni dopo camminando lungo l'albero (che diversamente dal caso di alberi veri significa "verso le foglie").

In tutti gli altri casi, proviamo a prendere una tupla knowledge(dopo esserci filtereditati per assicurarci di "vedere" solo le coppie con lo stesso primo elemento che vogliamo controllare), e proseguiamo da dove punta. La comprensione dell'elenco riguarda tutte le possibili tuple con cui continuare e chiama di verifynuovo in ciascun caso. Un vicolo cieco avrà solo un elenco vuoto qui e ritornerà nel falsecomplesso, e quindi non influenzerà l'istanza di cui verifyè stato chiamato.


Potresti aggiungere una breve spiegazione per le persone che non parlano fluentemente?
J Atkin,

Fortunatamente! Non lo faccio per ogni post fino a quando non viene richiesto.
Leif Willerts,

Ok grazie! (riempimento)
J Atkin,

Wow, questa è una spiegazione.
J Atkin,

2
Ho appena finito di leggere la prima metà di Learn you a haskell for great good!questo e ora capisco questo! (Questa risposta è in realtà ciò che mi ha spinto a saperne di più su haskell e FP, ed è davvero fantastico!)
J Atkin,

4

JavaScript, 265 263 byte

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

Immettere una stringa vuota per uscire.

Spiegazione

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

Potresti usare string.split(" ");?
J Atkin,

@JAtkin Ho usato .match(/\w+/g)per rimuovere la punteggiatura dalle parole.
user81655

L'ho visto, ma non .split(" ")sarebbe più breve o mi sto perdendo qualcosa? (Non conosco JavaScript)
J Atkin,

@JAtkin Se avessi usato .splitavrei anche dovuto usare .slice(0,-1)(due volte) perché B is a A.renderebbe Bereditario A.(con il .).
user81655

@JAtkin In realtà ho appena scoperto che split accetta espressioni regolari per poterlo usare .split(/\W/). Grazie per avermi indotto a cercarlo!
user81655
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.