Jouez-moi au golf!


26

Jouez-moi au golf!

L'héritage et la composition sont deux composants importants de la programmation orientée objet. Ensemble, ils permettent de créer des hiérarchies de classes simples mais puissantes pour résoudre les problèmes. Votre tâche consiste à analyser une série d'instructions sur une hiérarchie de classes et à répondre à des questions sur la hiérarchie.

Contribution

Une série d'énoncés et de questions sur une hiérarchie de classes, lus à partir d'un fichier ou d'une entrée standard, selon ce qui convient le mieux à votre langue. Si vous utilisez l'option file, le nom de fichier sera transmis comme premier argument à votre code (argument de fonction ou argument de ligne de commande, selon votre choix). Le format est le suivant:

<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'entrée sera toujours des déclarations, puis des questions. Tous les noms de classe commenceront par une lettre anglaise majuscule ( A-Z) et tous les noms de membres commenceront par une lettre anglaise minuscule ( a-z). Tous les noms sont sensibles à la casse - ABC123n'est pas la même classe que Abc123.

Il n'y aura pas d'héritage cyclique - si Bhérite de A, An'héritera pas de Bou de l'un des Benfants.

Seuls les noms de classe feront partie d'une hiérarchie - des instructions telles que foo is a bar.ou document has a name.ne se produiront pas.

Sortie

Une série de valeurs véridiques ou falsey, en tant que réponses aux requêtes, écrites sur la sortie standard ou en tant que valeur de retour de votre fonction. Si vous ne disposez pas de suffisamment d'informations pour répondre à une question (par exemple, des questions impliquant des noms que vous n'avez pas vus dans les déclarations), répondez par une valeur de falsey.

Cas de test

Cas 1:

Contribution:

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?

Sortie:

True
True
False

Cas 2:

Contribution:

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?

Sortie:

True
True
False
False
True

Règles

  • Vous pouvez répondre avec une fonction ou un programme
  • Les failles standard sont interdites
  • Ceci est le , donc la réponse correcte la plus courte en octets gagne
  • La réponse gagnante sera choisie dans une semaine

Bonne chance et que le POO soit avec vous!

Classement

L'extrait de pile au bas de cet article génère le classement à partir des réponses a) comme une liste des solutions les plus courtes par langue et b) comme un classement général.

Pour vous assurer que votre réponse apparaît, veuillez commencer votre réponse avec un titre, en utilisant le modèle Markdown suivant:

## Language Name, N bytes

Nest la taille de votre soumission. Si vous améliorez votre score, vous pouvez conserver les anciens scores dans le titre, en les barrant. Par exemple:

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

Si vous souhaitez inclure plusieurs nombres dans votre en-tête (par exemple, parce que votre score est la somme de deux fichiers ou que vous souhaitez répertorier les pénalités de drapeau d'interprète séparément), assurez-vous que le score réel est le dernier numéro de l'en-tête:

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

Vous pouvez également faire du nom de la langue un lien qui apparaîtra ensuite dans l'extrait de code:

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


Comment est Does Criminal have a name?égal à True? Tous les objets ont-ils un nom?
J Atkin

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

Ahh ... ça m'avait manqué.
J Atkin

Dois-je prendre toutes les entrées en même temps, ou puis-je les prendre ligne par ligne comme une console interactive? Si # 2, puis-je sortir un vrai \ falsey même si l'entrée est un état?
J Atkin

@JAtkin Tout à la fois ou ligne par ligne, votre choix. S'il s'agit d'une instruction, il ne devrait y avoir aucune sortie. Seules les questions obtiennent des réponses.
Mego

Réponses:


13

CJam, 59 octets

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

Cela se termine instantanément pour les deux cas de test.

Il imprime soit le deuxième nom de la question, soit 1(les deux sont véridiques), soit 0(la fausse).

Essayez-le en ligne dans l' interpréteur CJam .

Idée

En raison de la distinction entre les classes et les membres, le défi se résume à créer une précommande pour laquelle l'entrée fournit une définition partielle.

Nous définissons que xy si x est un y ou x a un y .

Pour le premier cas de test, l'entrée indique que BA , CB et Afoo . En raison de la transitivité, nous avons également Bfoo , CA et Afoo . De plus, en raison de la réflexivité, xx est toujours vrai.

Pour une entrée donnée, nous pouvons donc extraire la définition partielle de ≺ des énoncés, appliquer la transitivité un nombre de fois suffisant pour compléter la définition de ≺ et enfin répondre aux questions.

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#

2
C'est impressionnant étant donné que CJam n'a pas de cours: D
Beta Decay

C'est beau.
Mego

Les classes @BetaDecay sont essentiellement des ensembles imbriqués; les classes sont implémentées dans toutes les langues. Dites dans le premier exemple. C:{B:{A:{foo:{}}}}
A̲̲

8

Python 3, 431 331 308 octets

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)

Ceci est la version complète avec des commentaires

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)

Sortie pour le cas de test n ° 1:

True
True
False

Cas n ° 2:

True
True
False
False
True

J'ai supprimé les commandes de débogage pour plus de clarté dans le programme principal, mais si vous souhaitez les voir, regardez simplement dans l'historique


Au lieu d'utiliser global fin h(z), utilisez def h(z,f)et transmettez le global fin lors de l'appel. En fait, vous n'avez pas besoin h(z)du tout - mettez simplement le corps où vous l'appelez. Vous n'en avez pas besoin r=2et vous pouvez simplement vous en print(r)passer if, car vous devez générer une valeur de falsey pour les fausses requêtes. Vous pouvez renommer synpour zet raser il de plusieurs octets. Je ne pense pas que vous ayez besoin de la []compréhension de votre liste dans le premier any.
Mego

Vous utilisez également eune fois, vous pouvez donc supprimer la définition et simplement l'utiliser [a,b,c,d]. Au lieu de if s(i,g) is not None, faire if s(i,g)- re.Matchobjets sont toujours évalués à Truesi une correspondance est trouvée. Vous pouvez également supprimer 2 octets avec f[x]+=f[y].
Mego

@Mego Wow, merci pour tous les conseils. Je devrai les mettre plus tard.
J Atkin

Ce message vous aidera probablement beaucoup
Mego

@Mego Grand merci, sa baisse à 396 maintenant. Je posterai est sous peu.
J Atkin

4

Haskell, 157 octets

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

Donnez la chaîne à o. Je ne sais pas si faire xet v('extraire' et 'vérifier') des infixes coupe plus que de faire mapun infixe, ou si les deux sont possibles.

EDIT: Explication

Donc, (#)comment vous définissez un opérateur infixe, je l'utilise simplement comme raccourci pour mapappliquer une fonction à chaque élément d'une liste. En résolvant cela et l'autre alias l, en évitant l'opérateur d'application directe de fonction $et en ajoutant encore plus de parenthèses et d'espacement, et avec de vrais noms de fonction, nous arrivons à:

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) est une liste de listes de mots de chaque ligne de la chaîne d'entrée.

(=='?').last.last est un prédicat indiquant si la dernière lettre du dernier mot d'une ligne est un point d'interrogation, c'est-à-dire si la ligne est une question.

break casse la liste dans un tuple de la première partie sans questions (toutes les déclarations) et la partie de la première question sur (toutes les questions).

mapping extract nsur ceux-ci enlève de chaque liste de mots les éléments que nous voulons vraiment, le nth (qui dans les déclarations est le premier mot - donc n == 0, et dans les questions est le deuxième mot - donc n == 1) en utilisant l' !!opérateur et le dernier, à partir duquel nous doivent couper la dernière lettre (soit '.'ou '?') en utilisant init.

(Notez que j'ignore complètement la capitalisation, c'est parce que j'ignore complètement la distinction entre les classes et les membres, les membres ne sont que des feuilles d'un arbre construit par la base de connaissances (mais toutes les feuilles ne représentent pas des membres, elles peuvent également être des classes sans sous-classes ni membres) ), dans lequel chaque nœud enfant représente une sous-classe ou un membre de ce que représente son nœud parent. J'ai juste réalisé que c'était une mauvaise chose à faire dans les cas non couverts par OP. Éditera bientôt la solution.)

Maintenant, map (extract 0) knowledgeet map (extract 1) questionssont des listes de tuples de noms représentant une relation de sous-classe ou de membre du premier au second.

Les tuples dans map (extract 0) knowledgesont tous de vraies relations, ceux dans map (extract 1) questionssont maintenant mappés sur la verifyfonction, avec le premier argument défini sur map (extract 0) knowledge.

(Désormais, à l'intérieur verify, knowledgeest un nom de paramètre et fait référence à la extractliste de tuple déjà éditée.)

(En outre, lors de la lecture verify, notez que tandis que le ||(après le saut de ligne inélégant pour éviter le défilement horizontal sur SE) est une disjonction booléenne normale entre le cas `` réflexif '' et le `` récursif '', le orreplie sur une liste, c'est-à-dire vérifie s'il en existe l'élément de liste est vrai.)

Or, une relation est évidemment correcte si elle est réflexive. A proprement parler, non, un potaton'a pas avoir un potato(et il est même pas un dans le sens « est » est utilisé ici, comme dans « Un flic est un flic »), mais qui est juste la condition de terminaison qui couvre toutes les relations après descendre l'arbre (ce qui, contrairement aux vrais arbres, signifie «vers les feuilles»).

Dans tous les autres cas, nous essayons de prendre un tuple knowledge(après avoir filterédité pour nous assurer que nous ne 'voyons' que les paires avec le même premier élément que celui que nous voulons vérifier), et continuons d'où il pointe. La compréhension de la liste traite de tous les tuples possibles pour continuer et appelle à verifynouveau dans chaque cas. Une impasse aura juste une liste vide ici et reviendra falseglobalement, et n'influencera donc pas l'instance de verifycelle - ci qui a été appelée par.


Pourriez-vous ajouter une courte explication pour les personnes qui ne parlent pas couramment haskell?
J Atkin

Heureusement! Je ne le fais pas pour chaque article jusqu'à ce que je le demande
Leif Willerts

OK merci! (remplissage)
J Atkin

Wow, c'est une explication.
J Atkin

2
Je viens de terminer la lecture de la première moitié de Learn you a haskell for great good!et maintenant je comprends ça! (Cette réponse est en fait ce qui m'a incité à en savoir plus sur haskell et FP, et c'est tellement cool!)
J Atkin

4

JavaScript, 265 263 octets

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

Entrez une chaîne vide pour quitter.

Explication

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

Pourriez-vous utiliser string.split(" ");?
J Atkin

@JAtkin J'ai utilisé .match(/\w+/g)pour supprimer la ponctuation des mots.
user81655

Je l'ai vu, mais ne serait pas .split(" ")plus court ou est-ce que je manque quelque chose? (Je ne connais pas javascript)
J Atkin

@JAtkin Si j'utilisais .splitje devrais aussi utiliser .slice(0,-1)(deux fois) car B is a A.cela ferait Bhériter A.(avec le .).
user81655

@JAtkin En fait, je viens de découvrir que split accepte les expressions régulières pour que je puisse les utiliser .split(/\W/). Merci de m'avoir fait chercher ça!
user81655
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.