Basit bir sayı sistemi


19

Size basit bir sayı sisteminden bahsedeyim. (sadece bu meydan okuma için uydurdum)

Bu sistem işlevlerini içeren (), [], {}, ve <>.

1. ()

Ne zaman ()hiçbir argüman verilir, bu kadar değerlendirir 0.

Bir ()veya daha fazla bağımsız değişken verildiğinde, bağımsız değişkenlerin toplamını değerlendirir.

2. []

Ne zaman []hiçbir argüman verilir, bu kadar değerlendirir -1.

Bir []veya daha fazla argüman verildiğinde, ilk argümana eksi diğer argümanların toplamını değerlendirir.

3. {}

Ne zaman {}hiçbir argüman verilir, bu kadar değerlendirir 1.

Bir {}veya daha fazla argüman verildiğinde, bu argümanların çarpımını değerlendirir.

4. <>

Ne zaman <>hiçbir argüman verilir, bu kadar değerlendirir 1.

Bir <>veya daha fazla bağımsız değişken verildiğinde, ilk bağımsız değişken tamsayısının diğer bağımsız değişkenlerin ürününe bölünmesiyle değerlendirilir.

Senin görevin

Bu basit sayı sisteminde geçerli bir sayı içeren parantez (parantez dengeli, 0 saniyeye bölünme vb. Anlamına gelmez) içeren bir dize verildiğinde değerini yazdırın.

Test senaryoları

() -> 0
(()()) -> 0
([][]) -> -2
({}<>) -> 2
({}[]) -> 0
[] -> -1
[[][]] -> 0
[()<>] -> -1
{()} -> 0
{([]<>)} -> 0

Unutmayın, bu , bu yüzden en az baytlık kod kazanır.


13
Bunun için harika bir ismim var, ki bu tamamen uydurdum ve başka bir yerden alamadım: Brain-flake!
ETHproductions

4
@ETHproductions no
Oliver Ni


2
Bölme kayan bölümü veya tamsayı bölümü mü?
xnor

1
@Oliver İşlenenlerden biri veya her ikisi negatif olduğunda tamsayı bölümü nasıl çalışmalıdır? 4 beklenen sonuçlar nelerdir 5/3, 5/-3, -5/3ve -5/-3?
Martin Ender

Yanıtlar:


2

Dyalog APL , 94 bayt

o←{(⊂(1⊃⍵),⍺⍺⊃⍵),2↓⍵}⋄u←{(⊃⍵,⍺⍺1)⍺⍺⍵⍵/1↓⍵}⋄⍎⍕'+/o' '-u+o' '×/o' '÷u×o' '(⊂⍬),'[')]}>'⍳⌽⍞],'⊂⍬'

kullanımları ⎕IO←0

yerine geçer )]}>, bir yığın alan bir fonksiyon çağrısı ile siler, üst çerçeve üzerinde bir işlem uygulanır ve bir sonraki çerçeve için sonuç ekler (monadik operatör obunun için kullanılır; diyadik operatör ukolları daha karmaşık vakaları -ve ÷)

([{<yığına bir çerçeve ekleyen kodla değiştirilir ( (⊂⍬),)

sonuçtaki ifadeyi (APL'nin yürütme sırasına uyacak şekilde tersine çevrilmiş) bir boş çerçevenin ilk yığınıyla ( ⊂⍬) yürütür


5

Haskell'in 357 306 277 251 228 224 188 185 180 bayt

Belirgin bir yığını olan belirteç tabanlı ayrıştırıcı. (%)bir token yığını ve bir karakter alır ve ya (opcode, defaultnumber) veya (0, sayı) için ({[<ya da en üstteki sayıları ve bir opcode'u iter ve cevabını iter )}]>. Opkoplar bir ascii numaralandırma kesmekle kodlanır.

Bazı fikirler ödünç aldığım harika cevabı için @ChristianSievers'a Kudos .

Tek liner!

s%c|elem c"([<{",g<-div(fromEnum c)25=(g,[0,0,1,-1,1]!!g):s|(a,(o,n):b)<-span((==0).fst)s=(0,[foldr1(flip$[(+),quot,(-),(*)]!!(o-1))$snd<$>a,n]!!(0^length a)):b
snd.head.foldl(%)[]

Şimdi daha az hata yönetimi ile! Kullanımı:

*Main> map (snd.head.foldl(%)[]) ["()","(()())","([][])","({}<>)","({}[])","[]","[[][]]","[()<>]","{()}","{([]<>)}"]
[0,0,-2,2,0,-1,0,-1,0,0]

@ChristianSievers'a 14 + 3 bayt kaydettiğiniz için teşekkürler!

@Zgarb'a + 4 bayt kaydettiğiniz için teşekkürler!


1
(0,[0,0,1,-1,1]!!o):sBeşinci sırada ne dersiniz ?
Christian Sievers

Elbette @ChristianSievers!
Angs

Tanımlarını değiştirin !, böylece (s:_)!_=d sikinci durum olarak yapabilirsiniz . Ayrıca, x<-p$d<$>init a,y<-d$last ason durumda bağlayabileceğinizi düşünüyorum %.
Zgarb

@Zgarb teşekkürler! Değerlendirmeyi daha da birleştirmek için bir yol buldum.
Angs

1
Üçüncü satırda %sana parens etrafında bırakın _:bve g c.
Zgarb

3

Piton 2, 292 265 248 235 223 206 204 bayt

r=reduce
s=input()
for n in')]}>':s=s.replace(n,'),')
for a in'(*x:sum(x)','[a=-1,*x:a-sum(x)','{*x:r(int.__mul__,x,1)','<a=1,*x:r(int.__div__,x,a)':s=s.replace(a[0],'(lambda %s)('%a[1:])
print eval(s)[0]

Tüm parantezleri, parantezin yaptığı şeyi yapan bir lambda ile değiştirir, ardından ortaya çıkan Python kodunu değerlendirir. Gibi tırnak işaretleri içine girdi gerektirir '[<><>([]{})]'.

Bu program, parantez türünü her dizgideki ilk karakter olarak ve foranahtar kelimeden sonraki her şeyi lambdageri kalanı olarak saklar . Daha sonra yerine koymak için ilk karakteri kullanır; geri kalanı lambda gibi birleştirilir (lambda*x:sum(x))().

Ideone üzerinde deneyin!


3

PEG.js (ES6) , 132 bayt

x=a:[([{<]b:x*[)\]}>]{var x='([<'.indexOf(a)
b.length^1||b.push(0)
return~~eval(b.length?b.join(('+-/'[x]||'*')+' '):~-('10'[x]||2))}

Şimdi düzeltilmelidir.

açıklama

Daha okunabilir:

x=a:[([{<]
  b:x*
  [)\]}>]
{
  var x='([<'.indexOf(a)
  b.length^1||b.push(0)
  return ~~eval(
    b.length?
      b.join(('+-/'[x]||'*')+' ')
    :~-('10'[x]||2))
  )
}

PEG.js, ayrıştırma için özel olarak yapılmış Javascript'in genişletilmiş bir sürümüdür. ÇOK katı, bu yüzden kullanmak zorunda kaldım var. Ek olarak, dizelerin içinde parantez içeren bir hata var gibi görünüyor, bu da kodu önemli ölçüde şişirdi.

Başlamak için, kuralla xeşleşen abirden fazla ifade içerebilen veya içermeyen herhangi bir köşeli parantezle eşleşen bir kural tanımlarız x.

Her eşleşmenin yönetmesi için x, uzunluğu 1 bise iç eşleşmenin dizisine 0 ekleriz b.

Eğer bbireyin uzunluğu> 0, o zaman dizinini bulmak aiçinde ([<ve bir karakter almak +-/o dizini kullanarak. Sonuç (yani tanımsız ise aidi {), o zaman içine sonucu çevirmek *. Sonunda, bir alana yapışırız bve sonuca katılırız .

Eğer bbireyin uzunluğu = 0, o zaman dizinini bulmak aiçinde ([<ve bir karakter almak 10o dizini kullanarak. Sonuç (yani tanımsız ise aoldu {ya <), o zaman biz sadece eksiltme, Nihayet 2. içine sonucunu açın.

Sonunda, sadece ifadeyi değerlendirebilir ve sonucu ortaya koyabiliriz.


3

Perl, 113 + 2 = 115 bayt

İle koş -lp(2 bayt ceza).

/\W/,eval"sub $`\{\$#_?(shift)$&&$'1}"for qw'a+a:1- b-a:- c*c: d/c:';y/([{</a-d/;s/\W/0),/g;s/\pL\K/(/g;$_=eval

Daha okunabilir (not: bu "daha okunabilir sürüm" aslında çalışmaz, çünkü yorumları sözdizimsel olarak izin verilmeyen yerlere koydum):

              # -p option: read a line of input into $_ at program start
              # -l option: remove the final newline whenever reading
do {          # for each element of a list, given later:
  /\W/;       # place an initial identifier in $`, the next character in
              # $&, and the rest of the element in $'
  eval qq{    # then evaluate the following template, with substitutions:
    sub $` {  # define a subroutine named $`, that does this:
      \$#_ ?  # if there is more than one argument                   
      (shift) # then return the first argument $&-ed with
      $& &$'  # the result of a recursive call with the tail of the arguments
              # else (the "else" is a colon taken from $', not the template)
      1       # return (the remainder of $' applied to) 1
    }
  }
} for qw'     # specify the list by splitting the following on whitespace:        
  a+a:1-      # a(head,tail) = len(tail>1) ? head+a(tail) : 1-1
  b-a:-       # b(head,tail) = len(tail>1) ? head-a(tail) : -1
  c*c:        # c(head,tail) = len(tail>1) ? head*c(tail) : 1
  d/c:        # d(head,tail) = len(tail>1) ? head/c(tail) : 1
';
y/([{</a-d/;  # replace ( [ { < with a b c d in $_
s/\W/0),/g;   # replace whitespace, punctuation in $_ with the string "0),"
s/\pL\K/(/g;  # place a ( after (\K) each letter (\pL) in $_
$_=eval       # evaluate $_ as a Perl program, storing the result back in $_
              # -p option: print $_ to the user at program end
              # -l option: output a newline whenever printing

Temel fikir, metin işleme yoluyla [()<>]Perl programına benzer bir girdiyi dönüştürmemiz b(a(0),d(0),0),; Perl sondaki virgülle gayet iyi. Daha önce, fonksiyonları tanımlanmış a, b, c, daynı etkiye sahip olduğu (), [], {}, <>biz uygularken dilden yapılar; her biri, tüm girdilerin doğru ayrıştırılmasını sağlamak için dahil edilen son argümanlarını (sondaki 0) dikkate almazlar ve baş ile kuyruğun ayrı olarak işlendiği fonksiyonel programlamada yaygın olarak görülen uygulamayı kullanarak çalışırlar. Çünkü b(e,f,g,0)araçlar e-f-g, yani ilk argümanını özel olarak aele alırken , argümanlarını simetrik ( a(e,f,g,0)araçlar e+f+g) olarak ele alırsak,aözyinelemeli ve barayarak a. cve dbenzer bir ilişkiye sahipler. Bu işlevlerin dördü de birbirine çok benzer, bu yüzden bunları ayrı ayrı uygulamak yerine çalışma zamanında üretiyoruz; bir dizedeki dört işlev için de geçerli olan bir şablonu saklarız, ardından şablonu şablonun içine karakterler koyarak işlevler oluştururuz.

Perl /kayan nokta bölüşümü {}yaptığı için , uygulanan da yapar. Bunun kendi başına bir sorun olmadığını ya da -Minteger(tüm aritmetik işlemlerin tamsayı işlemleri olduğu bir dil değişkeninin seçilmesi) ücretsiz olduğunu varsayıyorum, aksi takdirde Perl'de bir tamsayı bölümü yazarak fazladan bayt harcamak zorunda kalacağım, bu da sorunun temelde ne olduğu gibi görünmüyor. (Sana değişen dört bayt harcamak zorunda düşünüyorum (shift)için int+(shift);. Bu test değil)


2

Octave, 215 206 198 bayt

S='sum(x(:))-sum(x(2:end))';Y='(@(x)isempty(x)';c=']) ';[~,~,u]=unique(['()<>[]{}',input('')]);eval([{'sum([',c,[Y,'+fix((',S,')/prod(x(2:end))))(['],c,[Y,'*-1+',S,'*2)(['],c,'prod([',c}{u(9:end)}])

çevrimiçi dene


2

PHP 315 300 285 258 250 244 bayt

for($s=$argv[1];$r=!$r;)foreach(["(+)1","[-]0","{*}2","</>2]as$p)if(preg_match("#$e$p[0]([-_\d]*)$e$p[2]#",$s,$m)){if(""==$v=strtok($m[1],_))$v=$p[3]-1;while(""<$n=strtok(_))eval("\$v$p[1]=$n;");$s=strtr($s,[$m[$r=0]=>_.$v]);}echo substr($s,1);

alt ifadeleri alt çizgi + değeri ile değiştirir; döngü yineleme değiştirilmediğinde kesiliyor.

C ile tanıştığımdan bu yana 19 yıl, PHP ile 17 yıl;
bu ilk defa strtokmantıklı ... 24 bayt tasarruf etmeye yardım ediyor!

Yıkmak

for($s=$argv[1];    // take input from argument
    $r=!$r;)        // toggle $r; loop until no replacement has taken place
    foreach(["(+)1","[-]0","{*}2","</>2]as$p) // loop through operations
        if(preg_match("#$e$p[0]([-_\d]*)$e$p[2]#",$s,$m))   // find a match
        {
            if(""==$v=strtok($m[1],_))  // init $v with first token from sub-match
                $v=$p[3]-1;             // if no token, init with default value
            while(""<$n=strtok(_))      // loop through tokens
                eval("\$v$p[1]=$n;");       // operate
            $s=strtr($s,[$m[$r=0]=>_.$v]);  // reset $r; replace match with underscore+value
        }
echo substr($s,1);  // print result

@Oliver burada kimseyi dövmüyor; ama eğlence için teşekkürler!
Titus

2

ES6 (Javascript), 250, 171, 154, 149, 147 bayt

Saf bir Javascript sürümü.

"Metaprogramlama" (buradaki diğer cevapların çoğu gibi), bir dizi doğrudan metin ikamesi uygulayarak (yani program yapısını olduğu gibi tutarak) giriş programı metnini karşılık gelen bir Javascript programına dönüştürür.

Muhtemelen daha fazla golf olabilir.

GÜNCELLEME (v2.1)

  • Eksi iki bayt (üçlü ifadede parantez kaldırıldı)
  • Sonuç çıkarma için değişken kullanarak ve fazladan "[]" kurtulmak için 5 bayt daha kapalı

GÜNCELLEME (v2)

ES dizilerindeki virgüllerin tamamen geçerli olduğunu fark ettik, bu yüzden virgül normalleştirme kodunun tamamı kaldırılabilir. Ayrıca @Titus tarafından alfabe aramayı optimize etme konusunda mükemmel bir tavsiye izledi.

GÜNCELLEME (v1)

Yinelenen "değiştir" takma adı kaldırıldı.

GÜNCELLEME (v1)

  • Daha iyi bir alfabe kullanın: () => 1+ [] => 0 {} => 2 * <> => 2 / (her karakter doğrudan bir değer veya operatör olarak yeniden kullanılabilir)

  • Reduce (), replace () ile değiştirildi (alfabe eşleme)

  • Sabit hat içi, açık ve kapalı braket işlemlerini tek adımda birleştirdi

Golf (v2.1)

s=>eval("o="+s.replace(/./g,r=>"2+1-3*3/"["()[]{}<>".indexOf(r)]).replace(/\d\D?|\D/g,r=>r[1]?r[0]-2+",":r*1?'([':`].reduce((r,a)=>r${r}a)),`)+"o

Golf (v1)

(s,A="(2)+[1]-{3}*<3>/")=>eval(s[R="replace"](/./g,r=>A[A.indexOf(r)+1])[R](/\d\D?|\D/g,r=>r[1]?r[0]-2+",":(r[0]*1?'([':`].reduce((r,a)=>r${r}a)),`))[R](/,(\])|,$/g,"$1"))    

Golf (v0)

([...s],A="(a)b[c]d{e}f<g>h",R="replace")=>eval(s.reduce((r,c)=>r+=A[A.indexOf(c)+1],'')[R](/ab|cd|ef|gh/g,r=>({d:-1,b:'0'}[r[1]]||1) + ',')[R](/[aceg]/g,"([")[R](/[bdfh]/g,r=>`].reduce((r,a)=>r${"+*-/"["bfdh".indexOf(r)]}a)),`)[R](/,(\])|,$/g,"$1"))

Açıklandı (v0)

//BEGIN 

//s - input text, A - alphabet, R - "String.replace()" alias
E=([...s],A="(a)b[c]d{e}f<g>h",R="replace")=>eval(

//Replace input alphabet by a more friendly one, to avoid too much escaping and quoting
// () - ab, [] -cd, {} - ef, <> - gh
s.reduce((r,c)=>r+=A[A.indexOf(c)+1],'')

//Replace no-arg invocations with a corresponding constant value
// () => 0, [] => -1, {} => 1, <> => 1      
[R](/ab|cd|ef|gh/g,r=>({d:-1,b:'0'}[r[1]]||1) + ',')

//Replace opening brackets with "(["
[R](/[aceg]/g,"([")

//Replace closing brackets with "].reduce(...)),"
//An arithmetic operation to apply (+-*/) is chosen based on the bracket type 
//and is substituted into the template 
[R](/[bdfh]/g,r=>`].reduce((r,a)=>r${"+*-/"["bfdh".indexOf(r)]}a)),`)

//Strip excessive commas
[R](/,(\])|,$/g,"$1")
);

//END: eval() the result


Example:
E("{([]<>()<>{})(<><>)}")
=> eval("([([-1,1,0,1,1].reduce((r,a)=>r+a)),([1,1].reduce((r,a)=>r+a))].reduce((r,a)=>r*a))")
=> 4

Ölçek

E=([...s],A="(a)b[c]d{e}f<g>h",R="replace")=>eval(s.reduce((r,c)=>r+=A[A.indexOf(c)+1],'')[R](/ab|cd|ef|gh/g,r=>({d:-1,b:'0'}[r[1]]||1) + ',')[R](/[aceg]/g,"([")[R](/[bdfh]/g,r=>`].reduce((r,a)=>r${"+*-/"["bfdh".indexOf(r)]}a)),`)[R](/,(\])|,$/g,"$1"))

T=(s,a)=>{
    console.log(s,r=E(s),r==a?"OK":"NOT OK");
}

T("()",0)
T("(()())",0) 
T("([][])",-2)
T("({}<>)",2) 
T("({}[])",0) 
T("[]",-1)
T("[[][]]",0) 
T("[()<>]",-1) 
T("{()}",0) 
T("{([]<>)}",0)

Test Çıkışı

() 0 OK
(()()) 0 OK
([][]) -2 OK
({}<>) 2 OK
({}[]) 0 OK
[] -1 OK
[[][]] 0 OK
[()<>] -1 OK
{()} 0 OK
{([]<>)} 0 OK

1
V0 sürümünüz s.reduce((r,c)=>r+="abcdefgh"["()[]{}<>".indexOf(c)],'')(-5) ile devam edebilir mi? öyleyse, indexOfbir değişkeni hatırlayabilir ve operatörü üçüncü bir dize değişmezinden alabilirsiniz.
Titus

2

Haskell, 1841791721616160159146148145 bayt

s%(c:i)|elem c")}]>"=([1?(*),sum,1?quot,(-1)?(-)]!!mod(fromEnum c)5$s,i)|(r,j)<-[]%i=(s++[r])%j
[v]%e=(v,e)
(v?_)[]=v
(_?o)s=foldl1 o s
fst.([]%)

Yinelemeli iniş, girdiye iplik geçiriyor çünkü Haskell. Her zamanki gibi, son satır bir tanım değildir, ancak sorunu çözen işlevi belirtir. Test etmek için, sonuncusu dışındaki satırları bir dosyaya koyun, yükleyin ve böyle bir şey yapın:

*Main> fst.([]%) $ "{([][][])([][])}"
6

İlham almak için @Zgarb'a ve çok sayıda ayrıntılı ipucuna ve çözümünden ve diğer ipuçlarından ilham almak için @Angs'a teşekkürler.

Bölmenin negatif tamsayılarla nasıl davranması gerektiği belirtilmemiştir. Her neyse, art arda kullanmak divyanlış görünüyor, çünkü divkalan değerlerin ürünü ile bir kez kullanmakla aynı değil . Şimdi kullanarak quot, <{}([][])[]>ve için aynı sonuçları alıyorum <{}{([][])[]}>.

Güzel, neredeyse okunabilir kod için ilk sürüme bakın. Ara sürümler her türlü güzel ve korkutucu kodu içerir ve bu sürümün anlaşılmasına yardımcı olur.


Açık tuples yerine tanımlayıp (!)=(,)kullanarak birkaç bayt kaydedebileceğinizi düşünüyorum !.
Zgarb

Eğer tanımlarsanız m xve d xolarak 1#xve 0#x, sen davaları birleştirebilir m[x]ve d[x]ben kaydeder düşünüyorum birine içine biraz da bayt.
Zgarb

@Zgarb Teşekkürler! Neredeyse ödemeden !ödemeyen son çifti neredeyse özledim . İkinci öneriniz kötü, neredeyse okunabilir kodum var ... Zeki!
Christian Sievers

Heh, tanımlamanın s%(c:i)=(s?c,i)ve s?')'=sum sdaha fazlasının çok daha kısa olacağını fark ettim , çünkü tekrarlananlardan kurtulabilirsiniz i. ..Hayır, bu büyük olasılıkla işe yaramaz s%(_:i).
Zgarb

1
Çeneleri gevşetin elemve divbu biraz daha bayt tasarruf etmelidir.
Zgarb

1

JavaScript (ES6), hayır eval, 156 bayt

f=s=>s==(s=s.replace(/(.) ?([- \d]*)[\]})>]/,(_,c,s)=>` `+(s?s.split` `.reduce((l,r)=>c<`<`?l- -r:c<`[`?l/r|0:c<`{`?l-r:l*r):c==`[`?-1:c==`(`?0:1)))?+s:f(s)

Açıklama: Normal ifade, ilk işlenmemiş kapanış braketini bulur ve (muhtemelen) karşılık gelen açılış braketiyle aradaki bağımsız değişkenlerle eşleşir. Argümanlar bölünmüş olan ve ne yazık ki (işleme göre azaltılır '(' ve '[' için uygun çift değildir +ve -) ya da daha sonra bağımsız değişken yoksa, uygun değeri, değerlerin karakter daha uygun suboptimal (hesaplanır Sonuç daha sonra diğer sonuçlardan ayırmak için bir öncü boşluk ile değiştirilir.Önce, daha fazla değişiklik yapılmayana kadar kendini tekrarlayan olarak çağırır, bu durumda sonuç değerini döndürür. Misal:

[()<>]
[ 0<>]
[ 0 1]
 -1

f ("([] [])") => 0 (2 yerine)
zeppelin

Diğer bazı testler de (sen benim test kodu verebilir benim için başarısız oluyor cevap olarak f ( "[]") => 0, "[]" Her başarısız testinin bir parçasıdır: muhtemelen nedeniyle, bir deneyin).
zeplin

@zeppelin Hata, bazı kötü golf nedeniyle oldu. Önceki bir sürüme geri döndüm, ama ne yazık ki bu bana birkaç bayt maliyeti.
Neil
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.