Sipariş işlemleri


13

Giriş

Çocuklukta ekleme ve çoğaltma konusunda ustalaştığınızı düşündüğünüzde bir nokta gelir, o zaman birisi gelir ve size şunları bildirir:

a * b + c = (a * b) + c! = a * (b + c),

ve daha önce size öğretildiği kadar basit veya doğrusal bir süreç olmadığını. İşlem sırası denilen bir şey olduğunu öğrenirsiniz . Bu, parantezlerin her şeyin önüne geçmesine gerek kalmadan, bir düzeyde tutarlılığı ve ifadeleri korumanın çok önemli bir yoludur.

Genel hikaye

Bir gün sokaklardaki panik sesiyle uyanıyorsunuz. " 2560 " ( aşırılık bir hex-ish bükümü ile "Operasyon Düzene Karşı Örgüt" Kısa) adlı aşırılık yanlısı bir grup , kötü yöntemlerini dünyadaki tüm nükleer silahların kontrolünü ele geçirmek için kullandı. Tüm gezegeni rehin tutuyorlar ve basit bir talepleri var: kabul edilen operasyon sırasını tersine çevirme veya ortadan kaldırma (parantezler önceliklerini korumak içindir). Yeni sistem PSADME (parantez, çıkarma / toplama, bölme / çarpma, üsler) olarak adlandırılır ve ifadeler sağdan sola değerlendirilir:

a - b - c = a - (b - c) = a + c - b

Günler geçer ve geçiş devam eder. Matematikçiler ve fizikçiler denklemlerini yeniden yazmakla meşgulken, bilgisayar bilimcileri matematiksel ifadelerin bilgisayarlar tarafından yorumlandığı modayı değiştirme göreviyle karşı karşıyadır. Yeni küresel derebeyler için çok fazla işkence yapmayı amaçlayan gizli bir isyancı programlama grubuna mensupsunuz - ve şans eseri, 2560 tarafından rastgele seçiliyor ve kıyaslama hesaplama programını üretmekle görevlendiriliyorsunuz.

Göreviniz

13+4=17=6.

Basitlik için, sağlanan tüm sayılar tamsayı olacak ve hesaplamalar tamsayı sonuçları üretecektir.

Kurallar ve puanlama

  • Program 128 karakter uzunluğundaki girişleri kabul etmelidir - diliniz / platformunuz daha düşük bir maksimum giriş uzunluğuna sahipse, bu kabul edilebilir bir bahanedir.
  • Standart boşluklar yasaktır.
  • Kazanan kod 18 Kasım'da (bu gönderi tarihinden itibaren 4 hafta) seçilecektir.
  • Golf için uygun sayılmayacak kod yayınlamaktan çekinmeyin. Bu eğlence ile ilgili. Bunu yapmanın ilginç bir yoluna sahipseniz, ancak kendiniz (veya yönteminizin doğası gereği) golf yapamıyorsanız, yine de gönderebilirsiniz.

Her zamanki gibi, kazanan kod, bazı eğlence değeri bonuslarıyla en az bayt sayısına sahip koddur:

  • Sağlanan ifadedeki karakterlerin kullanımından kaçınmak için -5 : + , - , ( , ) , ^ , * , /
  • -5 Hesaplamaları yapmak için, yöntem açık olmadan (saat veya gereksiz döngüler kullanılarak) standart bir bilgisayarda hesaplamak 5 dakikadan fazla (ancak 10 dakikadan fazla değil) sürer; Amaç, yeni derebeyleri kıyamet hesaplarını bozmaya çalışmadığınıza ikna etmektir .
  • - (5 + N) kodunuz içinde açık bir şekilde yazılacak 2560 üyeleri hakkında doğrudan saldırgan bir mesaj (N uzunluğunda, ön / arka boşluk dahil değil), neden olması gerektiğine dair saçma bir açıklama Orada. Kaldırılırsa kod düzgün çalışmamalıdır . Evet, eğlence değeri için ücretsiz puan.

Örnekler ve açıklamalar

[program] 2 - 2 - 2
2

2 - (2 - 2) = 2

[program] (2 + 2 * 3 + 3) / 3 + 3
4

(4 * 6) / (3 + 3) = 4

[program] 3 + 2 + 1 ^ 3
216

(3 + 2 + 1) ^ 3 = 216

[program] -5^2
25

(-5) ^ 2 = 25

[program] 32 / 8 * 3 - 1
2

32 / (8 * (3-1)) = 32/16 = 2


1 - 3 + 4 = 1 - 7? Sağdan sola bunu önerir, ancak bu PSADME'nin aksine çıkarma işleminden önce bir ekleme yapar, değil mi?
LLlAMnYP

1
@LLlAMnYP Toplama ve çıkarma aynı "grup" tadır, tıpkı PEMDAS'ta olduğu gibi sağdan sola gerçekleşir. Çarpma / bölme ile aynı. Daha çok benziyor P(SA)(DM)E.
Geobits

2
İfadenin sağdan sola işlenmesi amaçlanmamıştır; bunun yerine, eşit öncelikli işlemler ilk önce değerlendirilir. Yani 4/2 = 2, 2-1 = 1, ama normal (a / b) * c yerine a / b c = a / (b c). Umarım bu bir şeyleri temizler.
Jake

Muhtemelen bunu yapmanın en kolay yolu bir esnek / bizon veya lex / yacc dilbilgisi yazmaktır.

5
Kısaltmayı PADME olarak değiştirmelisiniz , çünkü böyle kötü bir örgütün üyeleri kesinlikle yeni Yıldız Savaşları üçlemesini orijinallerden daha fazla isteyecektir. Hatırlamak da daha kolay.
mbomb007

Yanıtlar:


9

Haskell, 134 bayt

import qualified Prelude as P
infixl 6 ^
(^)=(P.^)
infixr 8 + 
(+)=(P.+)
infixr 8 - 
(-)=(P.-)
infixr 7 /
(/)=P.div
infixr 7 *
(*)=(P.*)

Matematik operatörlerini yeni sabitlikler ve önceliklerle yeniden tanımlamak. Şimdi:

*Main> 32 / 8 * 3 - 1
2

1
Vay. Vay canına. Bu başka bir dilde bile mümkün müdür? +1
ETHproductions

Mathematica'da veya en azından benzer bir yaklaşımda mümkün olduğundan emindim, ancak çabucak farkettim, bunu yapacak bilgiye sahip değilim.
LLlAMnYP

1
Aşağıdaki öneri genellikle bu forumda kabul edilebilir olup olmadığından emin olmak için yeterince yeniyim. Tamamen kodunuza dayanır, ancak Haskell dosyasını oluşturmak ve GHCi'ye aktarmak için Perl kullanan bir bash betiğidir. Böylece, TÜM BYTE'yi kurtarırım. perl -e'$_="import qualified Prelude as Pl 6^r 8+r 8-r 7*r 7/";s/(. \d(.))/\ninfix\1\n(\2)=(P.\2)/g;s~\./~.div~;print'>a.hs;ghci a.hs Ne yazık ki, bir yazım hatası, oluşturulan kodun rakam ve sembol arasında bir boşluk olmamasına neden oldu, ancak yine de iyi çalışıyor. Bu, kodunuzun 5 bayt kaybedebileceği ve 'iyileştirmem' altesinden gelebileceği anlamına gelir.
Jake

@JArkinstall Değeri ne olursa olsun, cevabım sedkabuk kodu oluşturmak ve değerlendirmek için etkin bir şekilde kullanıyor . Muhtemelen iyi bir meta soru.
Dijital Travma

Bu doğrudur ve yaklaşımınızı gerçekten seviyorum - ancak, daha sonra başka bir dile okunan bir dilde bir dosya oluşturmak için bir araç (perl veya sed) kullanmak bir adım daha ileri görünüyor. Yukarıdaki kodu başka bir jeneratörle üretmenin bir yolu varsa (yöntem benim için açık olmasa da!) Aşırı şaşırmam ve kendimizi ayrıştırmada bulurduk. Bu izin verilebilirse, bu yaklaşımı kodunuza bile uygulayabilirsiniz (ve bu karttaki bazı zorluklara daha okunabilir dil cevaplarında gördüğüm birkaç örnek).
Jake

2

Exec uzantılı GNU sed -r, 398

s@ *\^ *@ ** @
:
s@\((-?[0-9]+)\)@\1@
t
s@(-?[0-9]+ - )+(-?[0-9]+ - -?[0-9]+)@\1(\2)@
t
s@(.*(^| |\())(-?[0-9]+ [-+] -?[0-9]+)(.*)@echo '\1'$((\3))'\4'@e
t
s@(-?[0-9]+ / )+(-?[0-9]+ / -?[0-9]+)@\1(\2)@
t
s@(.*(^| |\())(-?[0-9]+ [*/] -?[0-9]+)(.*)@echo '\1'$((\3))'\4'@e
t
s@(-?[0-9]+ \*\* )+(-?[0-9]+ \*\* -?[0-9]+)@\1(\2)@
t
s@(.*(^| |\())(-?[0-9]+ \*\* -?[0-9]+)(.*)@bash -c 'echo \1$[\3]\4'@e
t

Özellikle kısa değil, ama işi hallediyor.

sed önceliği ayrıştırmak için sorun değil ama aritmetik işlem yapmıyor Bu nedenle s, kabuğa gerekli aritmetiği dış kaynak için GNU sed exec uzantısını kullanıyoruz .

Şimdilik ^, ön ve arkada tam olarak bir boşluk olması dışında tüm operatörleri varsayar .

Test çıktısı:

$ cat psadme.txt 
2 - 2 - 2
(2 + 2 * 3 + 3) / 3 + 3
3 + 2 + 1 ^ 3
-5^2
32 / 8 * 3 - 1
$ sed -rf psadme.sed psadme.txt 
2
4
216
25
2
$ 

Güzel profil fotoğrafı. xD
Oliver Ni

1

JavaScript (ES6) 287 300

Hatayı Düzenle düzeltildi (sadece bir yazım hatası, 6 4 olmalıydı) - Snippet'in sonuna tam bir açıklama eklendi

Edit 2 Başka bir zorluk üzerinde çalışırken bazı iyileştirmeler buldu

Yine de aynı ayrıştırıcının bir başka minimum taşıyıcıyla taşınması. (karşılaştırmak Bu )

f=(x,W=[],Q=['('],z=1,h=p=>'+-*/^^))('.indexOf(p)>>1,C=n=>{for(;h(q=Q.pop())<h(n);W.push(q=='^'?Math.pow(a,b):eval(`a${q}b`)))a=W.pop(b=W.pop());z&&Q.push(q,n)})=>((x+')').replace(/\d+|\S/g,t=>t>'('?t>'('?~h(t)?z&&t=='-'?z=-z:C(t,z=1):(W.push(z*t),z=0):C(t,z=0):(Q.push(t),z=1)),W.pop())

// More readable
U=(x,W=[],Q=['('],z=1,
  h=p=>'+-*/^^))('.indexOf(p)>>1,
  C=n=>{
    for(;h(q=Q.pop())<h(n);
        W.push(q=='^'?Math.pow(a,b):eval(`a${q}b`)))
      a=W.pop(b=W.pop());
    z&&Q.push(q,n)
  }
)=>(
  (x+')')
  .replace(/\d+|\S/g,t=> 
       t>'('
       ?t>'('
       ?~h(t)
       ?z&&t=='-'?z=-z:C(t,z=1)
       :(W.push(z*t),z=0)
       :C(t,z=0)
       :(Q.push(t),z=1)
  ),
  W.pop()
)

// TEST
console.log=(...x)=>O.innerHTML+=x.join` `+'\n'

console.log(f('1 - 3 + 4')) // -6
console.log(f('2-2-2')) // 2
console.log(f('(2 + 2 * 3 + 3) / 3 + 3')) // 4
console.log(f('3 + 2 + 1 ^ 3')) // 216
console.log(f('-5^2')) // 25
console.log(f('32 / 8 * 3 - 1')) // 2

// Explained
X=(x,W=[],Q=['('],z=1,
  h=p=> // operator priority '+-:1, */:3, ^:5, ):7, (:9. If an operand then -1
     '+-*/^^))('.indexOf(p)>>1,
  C=n=>{ // Evaluate operators present on stack if they have upper priority, then push new operator on stack
    //console.log('Operand '+n)
    while( h(q = Q.pop()) < h(n) ) // pop operator from op stack and compare priority with current
    {
      // Pop operands from stack and push result
      b = W.pop();
      a = W.pop();
      r = q=='^' ? Math.pow(a,b) : eval('a'+q+'b')
      // console.log('Evaluate '+a+q+b+'='+r)
      W.push(r);
    }
    // if z == 0 do nothing, because the current operands are '(' and ')' that must be discarded
    // else Push again the last operator popped and the current one
    z && Q.push(q, n) // 
  }
)=>(
  (x+')')
  .replace(/[\d.]+|\S/g,t=> {
    //console.log('Q:'+Q,'W:'+W,'T:'+t,'U:'+h(t),'Z:'+z), // display status
    if (t == '(') 
    { // open parenthesis
      z = 1
      Q.push(t) // push a operator, its the highest priority
    }
    else if (t == ')')
    { //close parenthesis
      z = 0
      C(t) 
    }
    else if (h(t) < 0)
    { // operand
      W.push(z*t) // push operand with right sign
      z = 0 // set z to 0 to mark that we just pushed an operand, so next '-' (if present) is a binary operator 
    }
    else
    { // operator
      if (z && t=='-') // the minus is an unary operator (the only unary operator allowed is '-', '+' will not work)
        z =-z // change the sign
      else
        z = 1, // no unary minus
        C(t)
    }    
  }),
  W.pop() // return the value at top of operand stack
)
<pre id=O></pre>

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.