Golf Me An OOP!


26

Golf Me An OOP!

オブジェクト指向プログラミングの2つの重要なコンポーネントは、継承と構成です。一緒に、シンプルで強力なクラス階層を作成して問題を解決することができます。タスクは、クラス階層に関する一連のステートメントを解析し、階層に関する質問に答えることです。

入力

クラス階層に関する一連のステートメントと質問。ファイルまたは標準入力のいずれか、お使いの言語に最適なものから読み取られます。ファイルオプションを使用する場合、ファイル名はコードの最初の引数(関数引数またはコマンドライン引数のいずれか選択したもの)として渡されます。形式は次のとおりです。

<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の継承はAA継承ではないだろうBか、のいずれかBの子。

以下のような文-唯一のクラス名が階層の一部になるfoo is a bar.か、document has a name.発生しません。

出力

クエリに対する回答として、標準出力に書き込まれた、または関数の戻り値としての、一連の真実または偽の値。質問に答えるのに十分な情報がない場合(たとえば、声明に載っていない名前が関係する質問)、falsey値で答えてください。

テストケース

事例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

ルール

  • 関数またはプログラムで答えることができます
  • 標準的な抜け穴は禁止されています
  • これはなので、バイト単位の最短正解が勝ちます
  • 勝利の答えは一週間で選ばれます

幸運を祈ります。そして、OOPがあなたと共にありますように!

リーダーボード

この投稿の下部にあるスタックスニペットは、a)言語ごとの最短ソリューションのリストとして、b)全体的なリーダーボードとして、回答からリーダーボードを生成します。

回答が表示されるようにするには、次のマークダウンテンプレートを使用して、見出しから回答を開始してください。

## Language Name, N bytes

N提出物のサイズはどこですか。スコアを改善する場合、古いスコアを打つことで見出しに残すことができます。例えば:

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

ヘッダーに複数の数字を含める場合(たとえば、スコアが2つのファイルの合計であるか、インタープリターフラグペナルティーを個別にリストする場合)、実際のスコアがヘッダーの最後の数字であることを確認します。

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

言語名をリンクにして、スニペットに表示することもできます。

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


どのようにDoes Criminal have a name?等しいTrueですか?すべてのオブジェクトに名前がありますか?
Jアトキン

4
@JAtkin Criminal is a PersonPerson has a name
レトコラディ

ああ...私はそれを見逃していた。
Jアトキン

すべての入力を一度に取得する必要がありますか、それとも対話型コンソールのように行ごとに取得できますか?#2の場合、入力が文であってもtruthy \ falseyを出力できますか?
Jアトキン

@JAtkinすべてを一度にまたは行ごとに、選択。ステートメントの場合、出力はありません。質問のみが回答を取得します。
Mego

回答:


13

CJam、59バイト

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

これは、両方のテストケースですぐに終了します。

質問の2番目の名前、または1(両方とも真実)、または0(偽)を出力します。

CJamインタープリターでオンラインで試してください。

アイディア

クラスとメンバーの違いにより、最終的には、入力が部分的な定義を提供する事前順序を作成することが課題になります。

我々はそれを定義するXY IFF Xされ、YまたはXが有するyは

最初のテストケースのために、入力状態、そのBACB及びAFOO。そのため推移を、我々はまた、持っているBFOOCAおよびAFOOを。また、理由は反射性の、XX常に真です。

したがって、特定の入力に対して、ステートメントから≺の部分的な定義を抽出し、transitの定義を完了するのに十分な回数推移性を適用して、最後に質問に答えることができます。

コード

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
ベータ崩壊

これは美しいです。
メゴ

@BetaDecayクラスは本質的にネストされたセットです。クラスはすべての言語で実装されています。最初の例で言います。C:{B:{A:{foo:{}}}}
A̲̲

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 fin h(z)を使用する代わりに、呼び出し時にdef h(z,f)グローバルfinを使用して渡します。実際、あなたはまったく必要ありませんh(z)-あなたがそれを呼ぶところに体を置いてください。あなたは必要としないr=2、とあなただけ行うことができprint(r)ずにif、あなたが出力に偽のクエリのfalsey値を必要とするので、。名前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]
メゴ

@Megoすごい、すべてのヒントをありがとう。後で入れる必要があります。
Jアトキン

この投稿は、おそらく多くのあなたを助ける
MEGO

@Megoありがたいことに、今では396になりました。すぐに投稿します。
Jアトキン

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

文字列をに渡しますoxand v( 'extract' and 'verify')infixesがmapinfixを作成する以上にカットするかどうか、または両方が可能かどうかはわかりません。

編集:説明

だから、(#)中置演算子を定義する方法mapは、リストの各要素に関数を適用するための略記として使用します。これと他のエイリアスを解決しl、 'direct-function-application'-operator $を避け、さらに括弧とスペースを追加し、実際の関数名を使用して、以下に到達します。

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 は、質問のない最初の部分(すべてのステートメント)と最初の質問の部分(すべての質問)のタプルのリストを分割します。

mapextract nこれらに対してping を実行すると、各単語リストから実際に必要な要素、つまり、演算子と最後の要素を使用しnて、ステートメント内の最初の単語-so n == 0、質問内の2番目の単語-so n == 1!!が取得されますを使用して最後の文字('.'または'?')をカットする必要がありinitます。

(大文字と小文字の区別を完全に無視していることに注意してください。これは、クラスとメンバーの区別を完全に無視しているためです。メンバーは、知識ベースによって構築されたツリーのリーフであるだけです(ただし、すべてのリーフがメンバーを表すわけではなく、サブクラスもメンバーもないクラスである場合もあります)、すべての子ノードがその親ノードが表すサブクラスまたはメンバーを表します。これは、OPでカバーされていない場合にやるべきことです。すぐに解決します。

さて、map (extract 0) knowledgemap (extract 1) questionsは、1番目から2番目までのサブクラスまたはメンバーの関係を表す名前のタプルのリストです。

のタプルmap (extract 0) knowledgeはすべて真の関係であり、これらのタプルは最初の引数をに設定しmap (extract 1) questionsverify関数にマッピングされmap (extract 0) knowledgeます。

(これから、内部verifyknowledgeパラメータ名で、すでにを指しextract編タプルのリスト。)

(また、を読むときverifyは、||(SEでの水平スクロールを避けるためのエレガントな改行の後)は、「再帰的」と「再帰的」のケースの間の通常のブール論理和であることに注意してください。orそれをリストの上折り畳む、すなわちリスト要素はtrueです。)

現在、リレーションシップは再帰的であれば明らかに正しいです。厳密に言えば、いいえ、aにpotatoはa がありません(そして、「A Cop is a Cop」のように「is」がここで使用されているという意味では1つでもありません)potatoそれは後のすべての関係をカバーする終了条件です木を歩いています(実際のの場合とは異なり、「葉に向かって」を意味します)。

他のすべての場合では、タプルを取得しようとしknowledgefilterチェックしたい最初の要素と同じ最初の要素を持つペアのみを「確認」するためにedした後)、それが指す場所から先に進みます。リスト内包表記は、継続する可能性のあるすべてのタプルを処理しverify、それぞれの場合に再度呼び出します。行き止まりは、ここに空のリストがあり、false全体として返されるため、verify呼び出し元のインスタンスに影響を与えません。


ハスケル以外の流な人々に簡単な説明を加えていただけますか?
Jアトキン

幸せに!リクエストされるまで、すべての投稿に対してそれを行うわけではありません。
レイフウィラーツ

わかった、ありがとう!(フィラー)
Jアトキン

うわー、それはいくつかの説明です。
Jアトキン

2
前半を読み終えたところでLearn you a haskell for great good!、これが理解できました!(この答えは、実際に私がhaskellとFPについてもっと学ぶようになったきっかけで、すごいクールです!)
Jアトキン

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アトキン

@JAtkin .match(/\w+/g)言葉から句読点を削除するために使用します。
user81655

私はそれを見ましたが、.split(" ")短くなりませんか、何かが足りませんか?(私はJavaScriptを知らない)
Jアトキン

@JAtkinもし私が使用.split私も使用しなければならない.slice(0,-1)ので(2回)B is a A.になるだろうB継承A.(と.)。
user81655

@JAtkin実際、splitは正規表現を受け入れるため、を使用できることがわかりました.split(/\W/)。調べてくれてありがとう!
user81655
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.