Yalnızca kullanılamaz görünen bir programlama dili oluşturun


85

Hırsızların meydan okuma ipliği burada .

Polislerin görevi: Programlama için kullanılamaz görünen bir programlama dili tasarlayın, ancak bazı açık olmayan bir mekanizma ile hesaplamayı (ya da en azından görevin tamamlandığını) kabul edin.

Bir giriş dosyasından kod okuyan ve ardından bir şey yapan basit bir programlama dili tasarlamalısınız. Tercümanınızda çalışırken girişteki en büyük 3. sayıyı bulan bir çözüm programı hazırlamanız gerekir . Soyguncuların bir çözüm programı bulmasını mümkün olduğunca zorlaştırmanız gerekir. Soyguncular, yalnızca aklınızdan geçenleri değil, görevi gerçekleştiren herhangi bir çözümü yayınlayabilir.

Bu bir popülerlik yarışması. Polislerin amacı, tercümanı göndermeden 8 gün sonra çatlamadan hayatta kalırken mümkün olduğunca fazla oy almaktır. Bu amaçla, aşağıdaki uygulamalar yardımcı olacaktır:

  • Dilinizin anlambilimini doğru bir şekilde açıklamak
  • Okunabilir kod yazma

Aşağıdaki taktikler kesinlikle önerilmez:

  • Şifreleme, karma değerler veya diğer şifreleme yöntemlerini kullanma. RSA şifrelemesi kullanan bir dil görürseniz veya SHA-3 karma değeri 0x1936206392306'ya eşit değilse bir programı yürütmeyi reddediyorsanız, lütfen aşağı oy vermekten çekinmeyin.

Soyguncular mücadelesi: Polislerin tercümanlarında çalıştırıldığında girdideki en büyük üçüncü tam sayıyı bulan bir program yazın.

Bu, nispeten basittir. Bir polis cevabını kırmak için, tercümanında çalıştırıldığında görevi tamamlayan bir program oluşturmalısınız. Bir cevabı kırdığınızda, polisin gönderinize bağlayan cevabında "Kırık" yazan bir yorum gönderin. Her kim en çok polisi kırarsa soyguncunun ipliğini kazanır.

G / Ç Kuralları

  • Tercümanlar programın komut satırında bir dosya adı almalı ve çalıştırırken standart girdi ve çıktı kullanmalıdır.
  • Girdiler tekdüze olarak verilecek ve yalnızca karakterlerden 0ve 1(ASCII'de 48 ve 49) oluşacaktır . Bir dizi N kodlanır N 1s bir takip 0. 0Dosyanın sonundan önce bir ek var . Örnek: Dizi için (3, 3, 1, 14) giriş 11101110101111111111111100.
  • Girişin en az 3 sayı olması garanti edilir. Tüm sayılar pozitif tam sayılardır.
  • 1Program durmadan önce çıktı, basılan sayı ile değerlendirilecektir . Diğer karakterler göz ardı edilir.

Aşağıdaki örneklerde, ilk satır ondalık biçimde girdidir; ikincisi gerçek program girişidir; Üçüncüsü örnek bir çıktıdır.

1, 1, 3
101011100
1

15, 18, 7, 2, 15, 12, 3, 1, 7, 17, 2, 13, 6, 8, 17, 7, 15, 11, 17, 2
111111111111111011111111111111111101111111011011111111111111101111111111110111010111111101111111111111111101101111111111111011111101111111101111111111111111101111111011111111111111101111111111101111111111111111101100
111111,ir23j11111111111u

247, 367, 863, 773, 808, 614, 2
<omitted>
<contains 773 1's>

Polis cevapları için sıkıcı kurallar:

  • Gizliliğin engellenmesi nedeniyle güvenliği önlemek için, tercüman bu TIOBE endeksinin ilk 100'ünde bir dilde yazılmalı ve ücretsiz olarak kullanılabilir bir derleyici / tercümana sahip olmalıdır.
  • Tercüman, bu mücadeleden önce yayınlanan bir dili yorumlamamalıdır.
  • Tercüman görevinize uymalı ve dışarıda barındırılmamalıdır.
  • Tercüman deterministik olmalı
  • Tercüman taşınabilir olmalı ve kendi dilinin standardını takip etmelidir; tanımsız davranış veya böcek kullanmayın
  • Çözüm programı cevaba sığmayacak kadar uzunsa, onu üreten bir program yayınlamanız gerekir.
  • Çözüm programı yalnızca yazdırılabilir ASCII ve yeni hatlardan oluşmalıdır.
  • Çözüm programınızı, yukarıdaki örnek girdilerin her biri için kendi bilgisayarınızda 1 saatten daha az bir sürede çalıştırmanız gerekir.
  • Program herhangi tamsayılar az 10 için çalışması gerekir 6 ve en fazla 10 herhangi bir tamsayı sayıda 6 (ille de bir saatten az), toplam giriş uzunluğu en fazla 10 olması koşuluyla 9 .
  • Güvende olmak için, bir polis 8 gün geçtikten sonra çözüm programını cevaba göre düzenlemelidir.

puanlama

En yüksek puanla ve pozitif bir puanla güvende olan polis bu soruyu kazanır.


Bunu açıkça ifade etmiyorsunuz, ancak polisin tercümanı cevaplarında yazıp göndermesi gerektiğini varsaymakta haklı mıyım?
Mavi

@muddyfish Evet, tercümanın polis yanıtının içeriği olması gerekir.
feersum

1
@ kirbyfan64sos Çıktı, program durmadan önce yazdırılan 1 sayı ile değerlendirilecektir. Diğer karakterler göz ardı edilir.
mbomb007


20
Bu zorlukla kendimi inek gibi çektim. Bir programlama dili oluşturulan ve daha sonra dil bile aslında öğrenmek için sadece işe yarayabilir görmek için görevi programlama saatlerce oldu kullanılamaz.
Sanchises

Yanıtlar:


24

Değişme (güvenli)

ShapeScript

ShapeScript doğal olarak oluşan bir programlama dilidir. Şekil değiştiriciler (veya çağrılmayı tercih ettikleri gibi Değişiklikler ), verileri işlemelerine izin veren bir dizi talimata dönüşebilir.

ShapeScript, nispeten basit bir sözdizimine sahip yığın temelli bir dildir. Şaşırtıcı olmayan bir şekilde, yerleşiklerinin çoğu, dizelerin şeklini değiştirmekle ilgileniyor. Karakter karakterleriyle şu şekilde yorumlanır:

  • 've "bir dize değişmezine başlayın.

    Eşleşen alıntı kaynak kodunda bulunana kadar, bu eşleştirme tırnak işaretleri arasındaki tüm karakterler bir dizgede toplanır ve ardından yığına itilir.

  • 0için 9tamsayıyı itme 0 ile 9 yığında. İki tamsayı 10ittiğini unutmayın .

  • ! yığından bir dize çıkar ve bunu ShapeScript olarak değerlendirmeye çalışır.

  • ? yığından bir tam sayı çıkar ve yığın öğesinin bir kopyasını bu dizinde iter.

    Dizin 0, en üstteki yığın öğesine (LIFO) ve endeks -1 ise en alttakie karşılık gelir.

  • _ yığından yinelenebilir bir şey çıkar ve uzunluğunu iter.

  • @ yığından iki öğe çıkar ve bunları ters sırayla iter.

  • $yığından iki dize çıkar ve en üstteki en üste geldiğinde en alttan birini böler. Sonuçta ortaya çıkan liste karşılığında itilir.

  • &bir dizge (en üstte) ve yığından yinelenebilir bir sayı çıkar ve dizeyi ayırıcı olarak kullanarak yinelemeye katılır. Elde edilen dize karşılığında itilir.

  • Piton Dünya'da Changelings yakın akrabaları olduğu için ShapeScript, gezegenimizde kullanılırsa, diğer tüm karakterler c iki öğe pop x ve y (üstteki) yığından, ve Python kodunu değerlendirmek girişiminde x c y.

    Örneğin, karakter dizisi 23+değerlendirilirken 2+3, karakter dizisi "one"3*değerlendirilir 'one'*3ve karakter dizisi 1''Adeğerlendirilir 1A''.

    Son durumda, sonuç geçerli Python olmadığından, Değişiklik, geçerli şeklinin öngörülmediğinden (sözdizimi hatası) şikayet eder, çünkü geçerli ShapeScript değildir.

Kodu çalıştırmadan önce, yorumlayıcı tüm kullanıcı girişini yığında bir dizge biçiminde yerleştirir. Kaynak kodu yürüttükten sonra tercüman tüm öğeleri istif üzerine basacaktır. Aradaki herhangi bir parça arızalanırsa, Değişiklik mevcut şeklinin yetersiz olduğundan şikayet edecektir (çalışma zamanı hatası).

Şekil değiştirme

Doğal hallerinde, Değişiklikler ShapeScript şeklini almaz. Bununla birlikte, bazıları potansiyel bir kaynak koduna dönüştürebilir (bu zorunlu olarak faydalı ve hatta sözdizimsel olarak geçerli değildir).

Tüm uygun Değişiklikler aşağıdaki doğal biçime sahiptir:

  • Tüm satırlarda aynı sayıda karakter bulunmalıdır.

  • Tüm satırlar yazdırılabilir ASCII karakterlerinden oluşmalı ve ardından tek bir satır beslemeli olmalıdır.

  • Satır sayısı, satır başına yazdırılabilir karakter sayısı ile eşleşmelidir.

Örneğin, bayt sırası ab\ncd\nuygun bir Değişimdir.

ShapeScript'e geçme girişiminde, Değişiklikler aşağıdaki dönüşüme uğrar:

  • Başlangıçta, kaynak kodu yoktur.

  • Her satır için aşağıdakiler gerçekleşir:

    • Changeling'in akümülatörü sıfıra ayarlanmış.

    • Satırın her bir c karakteri için (takip eden satır beslemesi dahil), c'nin kod noktası , akümülatörün 2'ye bölünmesiyle XORed'dir ve elde edilen kod noktasına karşılık gelen Unicode karakteri, kaynak koduna eklenir.

      Daha sonra, c'nin kod noktası ile bir boşluğun (32) kod noktası arasındaki fark akümülatöre eklenir.

Yukarıdakilerin herhangi bir kısmı başarısız olursa, Değişiklik mevcut şeklinin hoş olmamasından şikayet edecektir.

Tüm satırlar işlendikten sonra, Changeling'in (umarım geçerli) ShapeScript'e dönüşümü tamamlanır ve ortaya çıkan kod yürütülür.

Çözüm (ShapeScript)

"0"@"0"$"0"2*&"0"@+0?_'@1?"0"$_8>"1"*+@1?"0"+$""&'*!#

ShapeScript aslında oldukça kullanışlı olduğu ortaya çıktı; ilkellik testini bile yapabilir ( kanıt ) ve bu nedenle programlama dili tanımımızı yerine getirir .

Biraz değiştirilmiş bir sözdizimi ve daha iyi G / Ç ile GitHub'da ShapeScript'i yeniden yayımladım .

Kod aşağıdakileri yapar:

"0"@    Push "0" (A) and swap it with the input string (S).
"0"$    Split S at 0's.
"0"2*   Push "00".
&       Join the split S, using "00" as separator.
"0"@+   Prepend "0" to S.
        The input has been transformed into
        "0<run of 1's>000<run of 1's>0...0<run of 1's>0000".
0?_     Push a copy and compute its length (L).
'       Push a string that, when evaluated, does the following:
  @1?     Swap A on top of S, and push a copy of S.
  "0"$    Split the copy of S at 0's.
  _8>     Get the length of the resulting array and compare it with 8.
          If this returns True, there are more than eight chunks, so there are
          more then seven 0's. With two 0's surrounding each run of 1's and
          three extra 0's at the end, this means that there still are three or
          more runs of 1's in the string.
  "1"*    Push "1" if '>' returned True and "" if it returned False.
  +       Append "1" or "" to A.
  @1?     Swap S on top of A, and push a copy of A.
  "0"+    Append "0" to the copy of A.
  $       Split S at occurrences of A+"0".
  ""&     Flatten the resulting array of strings.
'       This removes all occurrences of "010" in the first iteration, all
        occurrences of "0110" in the second, etc., until there are less than
        three runs of 1's left in S. At this point, A is no longer updated,
        and the code inside the string becomes a noop.
*!      Repeat the code string L times and evaluate.
#       Drop S, leaving only A on the stack.

Çözüm (Changeling)

"1+-.......................
""B1.......................
"" 2)+7....................
"" 2)=<....................
""( $86=...................
""B8=......................
""247......................
""]`b......................
""B1.......................
""%D1=.....................
""%500=....................
""%&74?....................
""%&#.2....................
""%[bdG....................
""%D1=.....................
""%<5?.....................
""%:6>.....................
""%&65?....................
""%&-%7>...................
""%D1=.....................
""%500=....................
""%&74?....................
""%&,)5>...................
""%&%,79...................
"" )$?/=...................
""),-9=....................
""# !......................

Tüm Değişen programlar gibi, bu kod da takip eden bir satır akışına sahip.

ShapeScript hemen herhangi bir karakterde hata yapar, anlamadı, ancak isteğe bağlı dizeleri doldurucu olarak itebilir ve daha sonra açabiliriz. Bu, her satıra (akümülatörün küçük olduğu başında) ve ardından bir açıklıktan yalnızca küçük miktarda kod koymamızı sağlar ". Bir sonraki satıra başlarsak "#, gerçek kodu etkilemeden dizgiyi kapatıp açarız.

Ek olarak, üç küçük engelin üstesinden gelmek zorundayız:

  • ShapeScript kodundaki uzun dize tek bir belirteçtir ve bir satıra sığamayacağız.

    Biz parçalar (bu dizeyi zorlayacak '@', '1?'daha sonra bitiştirmek edeceğiz, vs.).

  • Kod noktası _oldukça yüksek ve zorlamak '_'zor olacak.

    Ancak, değiş tokuşu geri almak için '_@'zahmetsizce, ardından başka biri tarafından '@'zorlanabileceğiz.

ShapeScript kod bizim Sahtekar gibi görünür üretecektir 1 :

"0""
"#@"
"#"0"$"
"#"0"2"
"#*&"0""
"#@+"
"#0?"
"#_@"
"#@"
"#'@'"
"#'1?'"
"#'"0'"
"#'"$'"
"#'_@'"
"#'@'"
"#'8'"
"#'>'"
"#'"1'"
"#'"*+'"
"#'@'"
"#'1?'"
"#'"0'"
"#'"+$'"
"#'""&'"
"#"+"77"
"#+*!*"
"#!#"

Bu dönüştürücü aracılığıyla yukarıdaki ShapeScript kodunu çalıştırarak Değiştirme kodunu buldum . 2

Tercüman (Python 3)

#!/usr/bin/env python3

import fileinput

def error(code):
  print("This shape is " + ["unpleasant", "unpurposed", "inadequate"][code - 1] + ".")
  exit(code)

def interpret(code):
  global stack
  stringing = 0
  for char in code:
    quote = (char == "'") + 2 * (char == '"')
    if quote or stringing:
      if not stringing:
        string = ""
        stringing = quote
      elif stringing == quote:
        stack.append(string)
        stringing = 0
      else:
        string += char
    elif char in "0123456789":
      stack.append(int(char))
    else:
      x = stack.pop()
      if char == '!':
        interpret(x)
      else:
        if char == '?':
          y = stack[~x]
        elif char == "_":
          y = len(x)
        else:
          y = stack.pop()
          if char == '@':
            stack.append(x)
          elif char == '$':
            y = y.split(x)
          elif char == '&':
            y = x.join(map(str, y))
          else:
            try:
              y = eval(repr(y) + char + repr(x))
            except SyntaxError:
              error(2)
        stack.append(y)

source = ""
lengths = []

for line in fileinput.input():
  if not line or sorted(line)[:2][-1] < " " or max(line) > "~":
    error(1)
  lengths.append(len(line))
  accumulator = 0
  for char in line:
    value = ord(char)
    try:
      source += chr(value ^ (accumulator >> 1))
    except:
      error(1)
    accumulator += value - 32

lengths.append(len(lengths) + 1)

if min(lengths) != max(lengths):
  error(1)

stack = ""

for line in fileinput.input("-"):
  stack += line

stack = [stack]

try:
  interpret(source)
except:
  error(3)

print("".join(map(str, stack)))

1 Her satır, rastgele çöplerle satır miktarına doldurulur ve satır beslemeleri aslında yoktur.
2 Alttaki sayılar, Değişim kodundaki 32 ile 126 arasında kalan en düşük ve en yüksek kod noktasını gösterir.


1
Xor / dönüşüm kullanımı için -1. ShapeScript dönüşümündeki değişiklik bana şifreleme gibi gözüküyor.
MegaTom

10
@ MegaTom Uygun gördüğünüz gibi oy kullanabilirsiniz, ancak sorular şifrelemeye yol açar, çünkü sadece soygunları önemli bir dezavantaja sokan polise bilinen bir anahtardır . Dönüşüm anahtarsız bir dönüşümdür.
Dennis

1
ShapeScript, 67 bayt: 0"#002?'+'&'0'$'0?2?-@2?>*+00'&!++'1'*'0'+@1?$0?''&@_2-2?*@+@"3*!@#. Yine de, bunun için bir Changeling bulmaktan vazgeçtim. Çoğunlukla işe yaramaz ifadelerle serpiştirilmiş olsalar bile, 20 bayttan daha fazlasını
bulamamıştım

2
@ MegaTom Aslında verilen çözümden dolayı oldukça hayal kırıklığına uğradım. % 92.9'u yararsız koddan daha akıllıca bir şey bekliyordum.
primo

2
@primo Biraz daha titrendi, ancak Python 2 ile de çalışan bu Changeling'i buldum . Ben bilmiyorum zeki cevabım, ancak kaçamak bir polis gönderme planım vardı için işe yaradı gibi görünüyor çatlak bulunabilir.
Dennis

30

Karışık (C ++ ile yazılmış), Kırık! Martin tarafından

Edit Martin kırdı. Çözümünü görmek için bağlantıya tıklayın. Benim de çözümüm eklendi.

Edit Sabit print-dkayıtlarını ve yığınları hem idare edebilmek için komutu. Bu, bir çözümde izin verilmeyen bir hata ayıklama komutu olduğundan, yorumlayıcının önceki sürümünü kullanan hiç kimseyi etkilememelidir.

Bu konuda hala yeniyim, bu yüzden cevabımda veya tercümanımda yanlış bir şey varsa, lütfen bana bildirin. Bir şey net değil ise lütfen açıklama isteyin.

Bunun çok zor olacağını hayal etmiyorum, ama umarım bir çeşit zorluk çıkarır. Karıştırmayı oldukça kullanışsız kılan şey, yalnızca işler uygun yerlerde olduğunda basılacağıdır.

-> Temel Bilgiler:

24 Yığın var, onları çağırıyoruz stack1, ... stack24. Bu yığınlar bir listede yaşıyor. Yani yığını herhangi programın başında, bu yığınları sıfır itti ve onlar doğru yerde başlamak i içinde i (biz endeksi C aksine 1'den başlayarak unutmayın ++) listede pozisyon. Bir program süresince, listedeki yığınların sırası değişecektir. Bu, komutları tartıştığımda açıklanacak nedenlerden dolayı önemlidir.

Kullanılabilecek 5 kayıt vardır. Onlar adlandırılır Alberto, Gertrude, Hans, Leopold, ShabbySam. Bunların her biri bir programın başında sıfıra ayarlanır.

Yani, herhangi bir programın başlangıcında, 24 yığın var, her birinin sayısı yığın listesinde endeksiyle eşleşen. Her yığında en üstte bir sıfır bulunur. Beş yazıcının her biri sıfıra başlatılır.

-> Komutlar ve Sözdizimi :

Karışık olarak kullanılabilen 13 komut (+1 hata ayıklama komutu) vardır. Onlar aşağıdaki gibidir

  • cinpushbu komut argüman gerektirmez. Komut satırı girişini soruda açıklanan şekilde bekler (diğer girdiler tanımlanmamış / tanımlanmamış sonuçlara yol açacaktır). Daha sonra giriş dizesini tamsayılara böler , örneğin 101011100-> 1,1,3. Alınan her giriş için, aşağıdakileri yapar: (1) , değere dayalı yığınların listesine izin verir. Söz konusu tamsayı değeri a olarak adlandırılsın . Eğer bir 10'dan küçükse o permütasyon yapar u . Eğer a , 9 ile 30 arasında (koşulsuz) ise, permütasyon yapar d . Aksi takdirde permütasyon yapar r . (2) Daha sonra iter birListede ilk olan yığının üstüne. Bunu kastetmediğime dikkat edin stack1( stack1listede ilk durumda olmasına rağmen ). Permütasyonlar aşağıda tanımlanmıştır. cinpushKullanıcı girişi almanın tek yolu bu olduğundan, herhangi bir çözümde görünmesi gerekir.
  • mov value registermovKomut temelde değişken atama olduğunu. O atar valueetmek register. valuebirkaç form alabilir: (1) bir tamsayı olabilir, örneğin 47 (2) farklı bir sicilin adı, örneğin Hans (3) örneğin 's' ile takip edilen bir yığının indeksi 4s. Bunun yığının numarasını değil, listedeki dizin olduğunu unutmayın. Bu nedenle, sayı 24'ü geçmemelidir.

    Bazı movörnekler:

    mov 4s Hans 
    mov Hans ShabbySam
    mov 9999 Gertrude
    
  • movfs index registerBu 'yığından taşıma' anlamına gelir. movKomuta benzer . Bir yazmaç tarafından indekslenmiş bir yığına erişebilmeniz için vardır. Örneğin, eğer Hans'ı daha önce 4'e eşitlerseniz ( mov 4 Hans) O zaman movfs Hans GertrudeGertrude'yi yığın 4'ün üstüne eşit olarak kullanabilirsiniz mov.

  • inc register register değerini 1 arttırır.
  • dec register Kayıt değerini 1 oranında azaltır.
  • compg value value registerBu 'daha büyük karşılaştırma' anlamına gelir. Kaydı iki değerden daha büyük olarak ayarlar. valuebir tamsayı, bir kayıt defteri veya yukarıdaki gibi 's' ile takip edilen bir yığın endeksi olabilir.
  • compl value value register 'daha düşük olanı karşılaştır' yukarıdakiyle aynı, daha küçük olanı alır.
  • gte value1 value2 registervalue1 >= value2Boolean değerini (1 veya 0 olarak) koyarsa kontrol eder register.
  • POP!! indexindexyığın listesinde indekslenen yığının tepesinden çıkar .
  • jmp labelkoşulsuz olarak etikete atlar label. Etiketler hakkında konuşmak için iyi bir zaman. Bir etiket 've' ile takip edilir. Tercüman etiketler için ayrıştırır, böylece etiketlerin yanı sıra arkaya da atlayabilirsiniz.
  • jz value labelsıfır labelise atlar value.
  • jnz value labelsıfır labeldeğilse atlar value.

    Etiket örnekleri ve atlama:

    this_is_my_label:
         jmp this_is_my_label
    
    mov 10 Hans
    jnz Hans infinite_loop
    
    infinite_loop:
         jmp infinite_loop
    
  • "shuffle" permutationİşte shuffle komutu. Bu, yığın listesine izin vermenizi sağlar. Argümanlar olarak kullanılabilecek üç geçerli permütasyon vardır l, fve b.

  • print registerBu, tüm yığınların başlangıç ​​konumlarında olup olmadığını kontrol eder, yani yığın i , yığın listesinde i indeksindedir . Bu durumda, değeri registerunary de basar . Aksi takdirde, kötü bir hata yazdırır. Gördüğünüz gibi, bir şey çıktısı almak için yığınların hepsi doğru yerlerde olmalı.
  • done!Bu, programa hatasız bir şekilde çıkmasını söyler. Program bitmeden bitiyorsa done!, konsola her bir yığının üstüne sayıyı ve ardından yığının numarası yazacaktır. Yığınların yazdırılma sırası, yığın listesinde göründükleri sıradır. Bir yığın boşsa, atlanır. Bu davranış hata ayıklama amaçlıdır ve bir çözümde kullanılamaz.
  • print-d valuebu, verilen yığının, yazıcının ya da tamsayının değerini yazdırır (yığın yığına i , isyukarıda açıklandığı gibi argüman olarak geçer ). Bu, bir çözümde izin verilmediğinden dilin bir parçası olmayan bir hata ayıklama aracıdır.

-> Tercüman kodu

Tüm ayrıştırma ana işlevde gerçekleşir. Bu, belirli komutlar için ayrıştırmayı bulacaksınız.

#include<fstream>
#include<iostream>
#include<string>
#include<stack>
#include<cmath>

using namespace std;

class superStack: public stack<long> {
    private:
        int m_place;
    public:
        static int s_index;


        superStack() {
            m_place = s_index;
            s_index++;
        }

        int place() {
            return m_place;
        }
};
int superStack::s_index=1;

superStack  stack1,stack2,stack3,stack4,stack5,stack6,stack7,stack8,stack9,stack10,stack11, \
            stack12,stack13,stack14,stack15,stack16,stack17,stack18,stack19,stack20,stack21,stack22,stack23,stack24;


superStack* stackptrs[]=    { \
                        &stack1,&stack2,&stack3,&stack4,&stack5,&stack6,&stack7,&stack8,&stack9,&stack10,&stack11, \
                        &stack12,&stack13,&stack14,&stack15,&stack16,&stack17,&stack18,&stack19,&stack20,&stack21,&stack22,&stack23,&stack24 \
                        };


long Gertrude=0;
long Hans=0;
long Alberto=0;
long ShabbySam=0;
long Leopold=0;


void SWAP( int i, int j) {    // 0 < i,j < 25

    i--;
    j--;


    superStack* tempptr = stackptrs[i];
    stackptrs[i]=stackptrs[j];
    stackptrs[j] = tempptr;



}

void u() {
    int list[3][4] = {
                        {1,9,6,13},
                        {2,10,5,14},
                        {17,19,20,18},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void d() {
    int list[3][4] = {
                        {3,11,8,15},
                        {4,12,7,16},
                        {22,24,23,21},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void r() {
    int list[3][4] = {
                        {2,17,8,24},
                        {4,18,6,23},
                        {9,10,12,11},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void l() {
    int list[3][4] = {
                        {1,19,7,22},
                        {3,20,5,21},
                        {14,13,15,16},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void f() {
    int list[3][4] = {
                        {20,9,24,16},
                        {18,11,22,14},
                        {1,2,4,3},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void b() {
    int list[3][4] = {
                        {19,10,23,15},
                        {17,12,21,13},
                        {5,6,8,7},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}

void splitpush(string input) {
    long value=0;

    for(long i=0;i<input.size();i++) {

        if(input[i]=='1'){
            value++;
        }
        else if(input[i]=='0' && value!=0 ) {
            if(value<10) {
                u();
            }
            else if (value<30) {
                d();

            }
            else {
                r();
            }
            (*stackptrs[0]).push(value);
            value=0;

        }
        else {
            break;
        }

    }

}

long strToInt(string str) { // IF STRING HAS NON DIGITS, YOU WILL GET GARBAGE, BUT NO ERROR
    long j=str.size()-1;
    long value = 0;
    for(long i=0;i<str.size();i++) {
        long x = str[i]-48;

        value+=x*floor( pow(10,j) );
        j--;
    }
    return value;
}

bool isEmpty(superStack stk) {
    if( stk.size()>0){return false; }
    else {return true;}

}    

long getValue(string str) {
    if(str=="ShabbySam") {
        return ShabbySam;
    }
    else if(str=="Hans") {
        return Hans;
    }
    else if(str=="Gertrude") {
        return Gertrude;
    }
    else if(str=="Alberto") {
        return Alberto;
    }   
    else if(str=="Leopold") {
        return Leopold;
    }
    else if(str[ str.size()-1 ]=='s'){
        str.pop_back();

        long index = strToInt(str)-1;

        if( !isEmpty( (*stackptrs[index]) ) ) {
            return (*stackptrs[index]).top();
        }
        else {
            cerr<<"Bad Expression or Empty Stack";


        }   
    }
    else {
        return strToInt(str);
    }

}

void printUnary(long i) {
    while(i>0) {
        cout<<1;
        i--;
    }
}

int main(int argc, char**argv) {

    if(argc<2){std::cerr<<"No input file given"; return 1;}
    ifstream inf(argv[1]);
    if(!inf){std::cerr<<"File open failed";return 1;}

    for(int i=0;i<24;i++) { 
        (*stackptrs[i]).push(0);         // Pre push a zero on every stack
    }

    string labels[20];
    unsigned labelPoints[20];
    int index=0;



    string str;
    while(inf) { //  parse for labels
        inf>>str;
        //cout<<inf.tellg()<<" ";
        if(inf) {
            if(str[str.size()-1]==':') {
                str.pop_back();
                bool alreadyExists = false;
                for(int i=0; i<index;i++){
                    if(labels[i] == str ) { alreadyExists=true;}
                }
                if(!alreadyExists) {
                    labels[index]=str;
                    labelPoints[index]= inf.tellg();
                    index++;
                }
            }

        }

    }
    inf.clear();
    inf.seekg(0,inf.beg);

    while(inf) { // parse for other commands 
        inf>>str;

        if(inf) {


            if(str=="cinpush") {
                string input;
                cin>>input;
                splitpush(input);
            }

            else if(str=="mov") {
                inf>>str;
                long value = getValue(str);

                inf>>str;
                if(str=="Gertrude"){Gertrude=value;}
                else if(str=="Hans"){Hans=value;}
                else if(str=="ShabbySam"){ShabbySam=value;}
                else if(str=="Alberto"){Alberto=value;}
                else if(str=="Leopold"){Leopold=value;}
                else {cerr<<"Bad register name. ";}

            }

            else if(str=="movfs") {
                inf>>str;
                long index = getValue(str);
                if(!isEmpty( *stackptrs[index-1] )) {
                    inf>>str;
                    long value = (*stackptrs[index-1]).top();
                    if(str=="Gertrude"){Gertrude=value;}
                    else if(str=="Hans"){Hans=value;}
                    else if(str=="ShabbySam"){ShabbySam=value;}
                    else if(str=="Alberto"){Alberto=value;}
                    else if(str=="Leopold"){Leopold=value;}
                    else {cerr<<"Bad register name.";}
                }
                else {
                    cerr<<"Empty Stack";
                }



            }

            else if(str=="inc") {
                inf>>str;
                if(str=="Gertrude"){Gertrude++;}
                else if(str=="Hans"){Hans++;}
                else if(str=="ShabbySam"){ShabbySam++;}
                else if(str=="Alberto"){Alberto++;}
                else if(str=="Leopold"){Leopold++;}
                else {cerr<<"Bad register name. ";}
            }
            else if(str=="dec") {
                inf>>str;
                if(str=="Gertrude"){Gertrude--;}
                else if(str=="Hans"){Hans--;}
                else if(str=="ShabbySam"){ShabbySam--;}
                else if(str=="Alberto"){Alberto--;}
                else if(str=="Leopold"){Leopold--;}
                else {cerr<<"Bad register name. ";}
            }


            else if(str=="compg") {
                inf>>str;
                long value1 = getValue(str);
                inf>>str;
                long value2 = getValue(str);
                inf>>str;
                long larger;
                if(value1>value2){larger = value1;}
                else {larger = value2;}

                if(str=="Gertrude"){Gertrude=larger;}
                else if(str=="Hans"){Hans=larger;}
                else if(str=="ShabbySam"){ShabbySam=larger;}
                else if(str=="Alberto"){Alberto=larger;}
                else if(str=="Leopold"){Leopold=larger;}
                else {cerr<<"Bad register name. ";}

            }
            else if(str=="compl") {
                inf>>str;
                long value1 = getValue(str);
                inf>>str;
                long value2 = getValue(str);
                inf>>str;
                long larger; //LARGER IS REALLY SMALLER HERE
                if(value1>value2){larger = value2;}
                else {larger = value1;}

                if(str=="Gertrude"){Gertrude=larger;}
                else if(str=="Hans"){Hans=larger;}
                else if(str=="ShabbySam"){ShabbySam=larger;}
                else if(str=="Alberto"){Alberto=larger;}
                else if(str=="Leopold"){Leopold=larger;}
                else {cerr<<"Bad register name. ";}

            }

            else if(str=="gte") {
                inf>>str;
                long value1= getValue(str);
                inf>>str;
                long value2= getValue(str);
                inf>>str;
                bool torf = value1 >= value2;

                if(str=="Gertrude"){Gertrude=torf;}
                else if(str=="Hans"){Hans=torf;}
                else if(str=="ShabbySam"){ShabbySam=torf;}
                else if(str=="Alberto"){Alberto=torf;}
                else if(str=="Leopold"){Leopold=torf;}
                else {cerr<<"Bad register name. ";}

            }

            else if(str=="lte") {
                inf>>str;
                long value1= getValue(str);
                inf>>str;
                long value2= getValue(str);
                inf>>str;
                bool torf = value1 <= value2;

                if(str=="Gertrude"){Gertrude=torf;}
                else if(str=="Hans"){Hans=torf;}
                else if(str=="ShabbySam"){ShabbySam=torf;}
                else if(str=="Alberto"){Alberto=torf;}
                else if(str=="Leopold"){Leopold=torf;}
                else {cerr<<"Bad register name. ";}

            }

            else if(str=="POP!!") {
                inf>>str;
                long index = getValue(str);
                index--; //because we (C++ and this interpreter) index differently
                if(!isEmpty( *stackptrs[index] )) {
                    (*stackptrs[index]).pop();
                }
                else {cerr<<"Can't POP!! from empty stack";}

            }

            else if(str=="push"){cerr<<" You can't. ";}

            /*
            else if(str[str.size()-1]==':') {
                str.pop_back();
                bool alreadyExists = false;
                for(int i=0; i<index;i++){
                    if(labels[i] == str ) { alreadyExists=true;}
                }
                if(!alreadyExists) {
                    labels[index]=str;
                    labelPoints[index]= inf.tellg();
                    index++;
                }
            }*/

            else if(str=="jmp") {
                inf>>str;
                for(int i=0;i<index;i++) {
                    if( labels[i]==str) {
                        inf.seekg( labelPoints[i], ios::beg);
                    }
                }
            }
            else if(str=="jz") {
                inf>>str;
                long value = getValue(str);

                if(value==0) {
                    inf>>str;
                    for(int i=0;i<index;i++) {
                        if( labels[i]==str) {
                            inf.seekg( labelPoints[i], ios::beg);
                        }
                    }
                }
            }

            else if(str=="jnz") {
                inf>>str;
                long value = getValue(str);

                if(value!=0) {
                    inf>>str;
                    for(int i=0;i<index;i++) {
                        if( labels[i]==str) {
                            inf.seekg( labelPoints[i], ios::beg);
                        }
                    }
                }
            }

            else if(str== "\"shuffle\"") {
                inf>>str;
                if(str=="l"){ l(); }
                else if(str=="f"){ f(); }
                else if(str=="b"){ b(); }
                else {cerr<<"Bad shuffle parameter";}

            }

            else if(str=="print") {

                for(int i=0;i<24;i++) {

                    if( (i+1) != (*stackptrs[i]).place() ) {
                        cerr<< "Sorry, your stacks are in the wrong place! You can't print unless you put them back! Exiting. ";
                        return 1;
                    }

                }
                inf>>str;
                if(str=="Gertrude"){printUnary(Gertrude);}
                else if(str=="Hans"){printUnary(Hans);}
                else if(str=="ShabbySam"){printUnary(ShabbySam);}
                else if(str=="Alberto"){printUnary(Alberto);}
                else if(str=="Leopold"){printUnary(Leopold);}
                else {cerr<<"Bad register name. ";}


            }

            else if(str=="done!") {return 0;}

            else if(str=="print-d" ){
                inf>>str;
                long value = getValue(str);
                cout<<str;
              }
        }

    }







    /*for(int i=1;i<25;i++) {
        (*(stackptrs[i-1])).push(i);
    }

    u();d();r();l();f();b();
    */

    cout<<"\n";
    for(int i=1;i<25;i++) {
        if( (*(stackptrs[i-1])).size()>0 ) {
            cout<<(*(stackptrs[i-1])).top()<<" "<<(*(stackptrs[i-1])).place()<<"\n";
            (*(stackptrs[i-1])).pop();
        }
    }
    /*
    for (int i=0;i<index;i++) {
        cout<<labels[i]<<": "<<labelPoints[i]<<"\n";
    }*/

    return 1;
}

-> Permütasyonlar Permütasyonlar yığın listesinin elemanlarına aşağıdaki şekilde izin verir:

Bunun anlamı

(Bunlar ayrıca tercüman kodunda da görünür. Bir tutarsızlık varsa, tercüman doğrudur.)

-> Basit Örnek

Bu iki basit program, 24'ten 1'e (unary'de) boşluk bırakmadan sayıları yazdırır.

mov 24 Hans
start:
    print Hans
    dec Hans
    jnz Hans start
done!

veya

mov 24 Hans start: print Hans dec Hans jnz Hans start done!

Onlar aynı program.

Açıklama ve Çözüm:

Martin'in de cevabında iyi bir açıklaması var .

Martin'in anladığı gibi, bu dil cep küpünden (aka 2x2 Rubik küpü) esinlenmiştir. 24 yığın, küpteki 24 ayrı kare gibidir. Permütasyonlar izin verilen temel hareketlerdir: yukarı, aşağı, sağ, sol, ön, arka.

Buradaki asıl mücadele, değerlere basıldığında sadece üç hareketin kullanılmasıdır: yukarı, aşağı ve sağ. Ancak, yığınları "karıştırırken" bu hareketlere erişemezsiniz. Sadece üç hamle daha var.

Görünüşe göre, üç hareketin her ikisi de aslında tüm grubu kapsar (yani, jeneratörlerdir), bu yüzden problem çözülebilir. Bu, 2x2 Rubik küpünün gerçekte sadece 3 hamlesini kullanarak çözebileceği anlamına gelir.

Tek yapılması gereken, diğer üçünü kullanarak yukarı, aşağı ve sağa hareketlerin nasıl geri alınacağını bulmak. Bu amaçla, GAP adında bir bilgisayar cebir sistemi kullandım .

Permütasyonları geri aldıktan sonra, en büyük üçüncü sayıyı bulmak oldukça önemsizdir.

cinpush
main:
    mov 1s ShabbySam
    POP!! 1
    jmp compare
    continue:
        gte 0 ShabbySam Leopold
        jnz Leopold end
        gte ShabbySam 9 Leopold
        jz Leopold uinverse
        gte ShabbySam 29 Leopold
        jz Leopold dinverse
        jnz Leopold rinverse
compare:
    gte ShabbySam Alberto Leopold
    jz Leopold skip
    mov Gertrude Hans
    mov Alberto Gertrude
    mov ShabbySam Alberto
    jmp continue
    skip:
        gte ShabbySam Gertrude Leopold
        jz Leopold skip_2
        mov Gertrude Hans
        mov ShabbySam Gertrude
        jmp continue
    skip_2:
        gte ShabbySam Hans Leopold
        jz Leopold continue
        mov ShabbySam Hans
        jmp continue
uinverse: 
    "shuffle" f
    "shuffle" f
    "shuffle" f
    "shuffle" l
    "shuffle" b
    "shuffle" l
    "shuffle" b
    "shuffle" b
    "shuffle" b
    "shuffle" l
    "shuffle" l
    "shuffle" l
    "shuffle" b
    "shuffle" b
    "shuffle" b
    "shuffle" l
    "shuffle" l
    "shuffle" l
    "shuffle" f
    jmp main
dinverse:
    "shuffle" f
    "shuffle" b
    "shuffle" l
    "shuffle" b
    "shuffle" b
    "shuffle" b
    "shuffle" f
    "shuffle" f
    "shuffle" f
    jmp main
rinverse: 
    "shuffle" b "shuffle" l "shuffle" f "shuffle" l "shuffle" b
    "shuffle" f "shuffle" f "shuffle" f "shuffle" b
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" b "shuffle" b "shuffle" b
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" f "shuffle" l "shuffle" f
    "shuffle" l "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l 
    "shuffle" f "shuffle" l "shuffle" l 
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" l "shuffle" l "shuffle" l "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" f "shuffle" l "shuffle" f "shuffle" l "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    jmp main
end:
    print Hans
    done!

2
Çatlak. :) Dilden gerçekten etkilendim!
Martin Ender

Vay, beklediğimden daha hızlıydı. Teşekkürler, yazdığı kadar kolay olduğunu bilmek beni çok mutlu etti.
Liam

Merak ediyorum, permiktasyon adlarını Rubik küpleriyle ilgili daha az açık bir şekilde değiştirmiş olsaydım, daha zor olurdu mı?
Liam

Onlar kesinlikle bir ipucu vardı, ama almazdı bence o kadar uzun farklı isimler olsaydı.
Martin Ender

Heh, görünüşe göre GAP üç giriş permütasyonunu ters çevirme konusunda özellikle akıllı olmuyordu. ;)
Martin Ender

22

Brian & Chuck , cracker_box tarafından Cracked

İki programın birbiriyle etkileşime geçtiği (muhtemelen ROCB'den ilham almış olan ) bir programlama dili fikri tarafından bir süredir ilgimi çekti . Bu zorluk, dili mümkün olduğu kadar az tutmaya çalışırken, bu kavramla başa çıkmak için güzel bir teşvikti. Tasarım hedefleri, dillerini tamamen Turing olarak tamamlarken, bölümlerinin her biri ayrı ayrı Turing olarak tamamlanmadı. Ayrıca, her ikisi de birlikte olsa bile, kaynak kodu manipülasyonundan yararlanmadan Turing-complete olmamalıdır. Ben düşünüyorum ben bunu başardım, ama resmen henüz bunların hiçbirinin kanıtlanmamıştır. Yani daha fazla uzatmadan sana sunuyorum ...

Kahramanlar

Brian ve Chuck iki Brainfuck benzeri programdır. Herhangi bir zamanda, bunlardan sadece biri Brian'dan başlayarak idam ediliyor. Buradaki yakalamak, Brian'ın hafıza bandının Chuck'ın kaynak kodudur. Chuck’ın hafıza bandı da Brian’ın kaynak kodudur. Ayrıca, Brian'ın teyp kafası da Chuck'ın talimat göstergesidir ve bunun tersi de geçerlidir. Bantlar yarı sonsuzdur (yani sağa sınırsızdır) ve sıfır (sıfırdan kaynak koduyla belirtilmediği sürece) sıfırlanmış, isteğe bağlı tam sayımlı tamsayıları tutabilir.

Kaynak kod aynı zamanda bir hafıza bandı olduğundan, komutlar teknik olarak tamsayı değerleri ile tanımlanır, ancak makul karakterlere karşılık gelirler. Aşağıdaki komutlar var:

  • ,( 44): STDIN'den geçerli bellek hücresine bir bayt okuyun. Bunu sadece Brian yapabilir. Bu komut Chuck için uygun değil.
  • .( 46): Geçerli bellek hücresini, modulo 256'yı STDOUT'a bayt olarak yazın. Bunu sadece Chuck yapabilir. Bu komut Brian için bir operasyon değil.
  • +( 43): Geçerli bellek hücresini arttırın.
  • -( 45): Geçerli bellek hücresini azaltır.
  • ?( 63): Geçerli bellek hücresi sıfırsa, bu işlem yapılmaz. Aksi takdirde, diğer programa el kontrolünü verin. Kullanılan programdaki teyp kafası üzerinde ?kalacaktır ?. Diğer programın teyp kafası, ilk komutu yerine getirmeden önce bir hücreyi sağa taşır (bu nedenle test olarak kullanılan hücre kendisi çalıştırılmaz).
  • <( 60): Bant kafasını bir hücre sola doğru hareket ettirin. Teyp kafası zaten bandın sol ucundaysa, bu işlem yapılmaz.
  • >( 62): Bant kafasını bir hücre sağa doğru hareket ettirin.
  • {( 123): Geçerli kafayı sıfıra ya da bandın sol sonuna ulaşana kadar bant kafasını sola doğru arka arkaya hareket ettirin.
  • }( 125): Geçerli hücre sıfır olana kadar bant kafasını art arda sağa hareket ettirin.

Program, aktif programın talimat işaretçisi, sağında başka talimat bulunmadığı bir noktaya ulaştığında sona erer.

Kaynak Kodu

Kaynak dosya aşağıdaki şekilde işlenir:

  • Dosya dizeyi içeriyorsa, dosya dizenin ```ilk oluşumu etrafında iki bölüme ayrılır. Önde gelen ve sondaki boşluklar sıyrılır ve ilk kısım Brian için kaynak kodu ve ikinci kısım Chuck için kullanılır.
  • Eğer dosya bu dizgiyi içermiyorsa, dosyanın ilk satırı Brian için kaynak ve Chuck için ikinci bölüm olarak kullanılacak (sınırlayıcı yeni satır dışında, boşluk yok).
  • Her _iki programdaki tüm oluşumlar NULL bayt ile değiştirilir.
  • İki bellek bandı, sonuçtaki dizgiye karşılık gelen karakter kodlarıyla başlatılır.

Örnek olarak, aşağıdaki kaynak dosya

  abc
```
0_1
23

Aşağıdaki başlangıç ​​kasetlerini verir:

Brian: [97 98 99 0 0 0 0 ...]
Chuck: [48 0 49 10 50 51 0 0 0 0 ...]

Çevirmen

Tercüman Ruby'de yazılmıştır. Bu gereken iki komut satırı bayrakları alır değil (bunlar gerçek dil şartnamenin bir parçası olmayan gibi) herhangi bir çözümün tarafından kullanılacak:

  • -d: Bu bayrakla Brian ve Chuck iki tane daha komut anladılar. !Her ikisi de hafıza bantlarının bir dize gösterimini yazdıracak, aktif program ilk önce listelenecektir (a ^mevcut bant kafalarını işaretleyecektir). @Bunu da yapacağız, ancak daha sonra programı derhal sonlandırın. Çünkü tembelim, programın son emri de olmadıkça bu ikisi de işe yaramaz, bu yüzden onları orada kullanmak istiyorsanız, tekrarlayın ya da onlardan sonra bir no-op yazın.
  • -D: Bu ayrıntılı hata ayıklama modudur. !Her onay işaretinden sonra olduğu gibi aynı hata ayıklama bilgilerini yazdıracaktır . @ayrıca bu modda çalışır.

İşte kod:

# coding: utf-8

class Instance
    attr_accessor :tape, :code, :ip

    OPERATORS = {
        '+'.ord  => :inc,
        '-'.ord  => :dec,
        '>'.ord  => :right,
        '<'.ord  => :left,
        '}'.ord  => :scan_right,
        '{'.ord  => :scan_left,
        '?'.ord  => :toggle,
        ','.ord  => :input,
        '.'.ord  => :output,
        '!'.ord  => :debug,
        '@'.ord  => :debug_terminate
    }

    OPERATORS.default = :nop

    def initialize(src)
        @code = src.chars.map(&:ord)
        @code = [0] if code.empty?

        @ip = 0
    end

    def tick
        result = :continue
        case OPERATORS[@code[@ip]]
        when :inc
            @tape.set(@tape.get + 1)
        when :dec
            @tape.set(@tape.get - 1)
        when :right
            @tape.move_right
        when :left
            @tape.move_left
        when :scan_right
            @tape.move_right while @tape.get != 0
        when :scan_left
            @tape.move_left while @tape.ip > 0 && @tape.get != 0
        when :toggle
            if @tape.get != 0
                @tape.move_right
                result = :toggle
            end
        when :input
            input
        when :output
            output
        when :debug
            result = :debug
        when :debug_terminate
            result = :debug_terminate
        end

        return :terminate if result != :toggle && @ip == @code.size - 1

        move_right if result != :toggle

        return result
    end

    def move_right
        @ip += 1
        if @ip >= @code.size
            @code << 0
        end
    end

    def move_right
        @ip += 1
        if @ip >= @code.size
            @code << 0
        end
    end

    def move_left
        @ip -= 1 if @ip > 0
    end

    def get
        @code[@ip]
    end

    def set value
        @code[@ip] = value
    end

    def input() end
    def output() end

    def to_s
        str = self.class.name + ": \n"
        ip = @ip
        @code.map{|i|(i%256).chr}.join.lines.map do |l|
            str << l.chomp << $/
            str << ' '*ip << "^\n" if 0 <= ip && ip < l.size
            ip -= l.size
        end
        str
    end
end

class Brian < Instance
    def input
        byte = STDIN.read(1)
        @tape.set(byte ? byte.ord : -1)
    end
end

class Chuck < Instance
    def output
        $> << (@tape.get % 256).chr
    end
end

class BrianChuck

    class ProgramError < Exception; end

    def self.run(src, debug_level=0)
        new(src, debug_level).run
    end

    def initialize(src, debug_level=false)
        @debug_level = debug_level

        src.gsub!('_',"\0")

        if src[/```/]
            brian, chuck = src.split('```', 2).map(&:strip)
        else
            brian, chuck = src.lines.map(&:chomp)
        end

        chuck ||= ""

        brian = Brian.new(brian)
        chuck = Chuck.new(chuck)

        brian.tape = chuck
        chuck.tape = brian

        @instances = [brian, chuck]
    end

    def run
        (puts @instances; puts) if @debug_level > 1

        loop do
            result = current.tick

            toggle if result == :toggle

            (puts @instances; puts) if @debug_level > 1 || @debug_level > 0 && (result == :debug || result == :debug_terminate)

            break if result == :terminate || @debug_level > 0 && result == :debug_terminate
        end
    end

    private

    def current
        @instances[0]
    end

    def toggle
        @instances.reverse!
    end
end

case ARGV[0]
when "-d"
    debug_level = 1
when "-D"
    debug_level = 2
else
    debug_level = 0
end

if debug_level > 0
    ARGV.shift
end

BrianChuck.run(ARGF.read, debug_level)

İşte soruna kendi (el yazısı) yazdığım çözüm:

>}>}>
brace left: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
brace left: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>} Append a bunch of 1s as a dummy list element:
+>+>+>+>+>+>+>+>+>+
Append two 1s and some code to the list; the first is a marker for later; the latter will be the integer
1: >+
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1: >+
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow right: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
_
{<<<<<<<<<{<{    Move back to the start
Read a character and subtract 48 to get actual 0 or 1
,------------------------------------------------
?   If 1 switch to Chuck otherwise continue
>}>}>>>>>>>>>}<<<<<<- Subtract 1 from the result to account for initial 1
?   If integer was positive switch to Chuck
@todo: process end
_
This code is run when reading 1:
}>}>>>>>>>>>}<<<<<<+ Move to the end of Chuck; skip one null cell; move to the end of the list
{<<<<<<<<<{<?   Move back to the code that resets this loop.
_
This code is run after finalising an integer:
change the code after the integer first
<<--<--<--}
Append two 1s and some code to the list; the first is a marker for later; the latter will be the integer
1: +
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1: >+
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow right: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
{<<<<<<<+<<{<{    Move back to the start; incrementing the list length
Read a character and subtract 48 to get actual 0 or 1
,------------------------------------------------
?   If 1 switch to Chuck otherwise continue
>}>}>>>>>>>>>}
Leave the resetting code, but remove the rest of the last list element:
<<<--<--<--
1: <-
question mk: <---------------------------------------------------------------
arrow left: <------------------------------------------------------------
brace right: <-----------------------------------------------------------------------------------------------------------------------------
1: <-
<{< Move back to the cell we reserved for the counter
<<<<<<-- decrement list size by two so we don't process the two largest elements
_

<{<<<<<<{<{<{<{<{>}>}>>>>>>> This is the beginning of the loop which decrements all list elements by 1
+ Add 1 to the running total
>>- Set marker of dummy list element to zero
_ Beginning of loop that is run for each list element
<{<<<<<<{<{<{<{<{>}>}>}>}+ set last marker back to 1
>>>>>>>>>> move to next marker
? Skip the next bit if we're not at the end of the list
<? Move back to the beginning of the loop
@ we should never get here
_
This is run when we're not at the end of the list
<<<- Set marker to 0 to remember current position
>>>>- Move to the current value and decrement it
? Move back to loop beginning if value is not zero yet
- Make element negative so it's skipped in the future
{<{<{>- Move to remaining list length and decrement it
? If it's nonzero switch to Chuck
>>>>>>>>->->->->->->->->->- Remove the dummy list to make some space for new code:
>}+ Fill in the marker in the list
{<<<<<<<<< Add some loop resetting code after the result:
brace left: +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
_
This loop adds a print command to Chuck's code while decrementing the result
>>>>>>>>}>>>>>}>>>>>} Move to the very end of Chuck's code and leave some space to seek the 1
print: ++++++++++++++++++++++++++++++++++++++++++++++
{<<<<<{<<<<<{<<<<<<<{<
- decrement the result
? if nonzero run loop again
At this point we just need to make Chuck seek for the 1 at the end of this code print it often enough
>>}>>>>>>>}>>>>>}
arrow right: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
<?1 Switch to Chuck which moves Brian's tape head onto the 1 and then prints it N times


```

_   Dummy cell to hold input
This code is run when reading a 1:
{<{<{<{ ensure we're at the start
}>}<? Skip 0 handling code and switch to Brian
_ This code is run after a 1 has been processed:
{<{<?

Bu kod tüm açıklamalar hiçbir-operatörleri kullanabilir ve tarafından atlanır çünkü olduğu gibi çalıştırılabilir olduğunu {ve }.

Temel fikir:

  1. Listeye yeni bir sıfır elemanı ekleyin (Chuck'ın bandının sonunda) ve liste uzunluğunu 1 arttırın.
  2. Biz 1s okurken , o elemanı arttır.
  3. A okurken 0biraz temizlik yapın. Ortaya çıkan tamsayı sıfırdan büyükse, 1'e geri dönün.

    Şimdi Chuck'ın kasetinin sonundaki giriş numaralarının bir listesini aldık ve listenin uzunluğunu biliyoruz.

  4. Listenin uzunluğundan 2'yi çıkarın (aşağıdaki adımlar en büyük iki unsuru yok sayar), bunu çağır N.

  5. Ancak N > 0, çalışan toplamı artırın ve ardından tüm liste öğelerini azaltın. Bir liste öğesi sıfıra geldiğinde, azalır N.

    Bunun sonunda, koşu toplamı girdideki en büyük üçüncü sayıyı içerecektir M.

  6. Chuck'ın kasetinin sonuna Mkopyalarını yaz ..

  7. Chuck'ta 1Brian'ın kasetinde bir arama yap .ve sonunda oluşturulanları çalıştır .

Bunu bitirdikten sonra bazı yerlerde oldukça basitleştirebileceğimi fark ettim. Örneğin, bu sayacı takip etmek ve bunları .Chuck'ın kasetine yazmak yerine, 1tüm liste öğelerini azaltmadan önce her defasında hemen baskı yapabilirim . Ancak, bu koda değişiklik yapmak oldukça acı verici bir durum, çünkü her yerde diğer değişiklikleri yayıyor, bu yüzden değişikliği yapmaktan rahatsız olmadım.

İlginç olan, listenin nasıl takip edileceği ve nasıl yineleneceği. Numaraları sadece Chuck'ın kasetinde saklayamazsınız, çünkü o zaman liste elemanlarından birindeki bir durumu kontrol etmek istiyorsanız, listenin geri kalanını geçerli kod içerebilecek şekilde yürütme riskiyle karşı karşıya kalırsınız. Ayrıca listenin ne kadar süreceğini de bilmiyorsunuz, bu yüzden sadece Chuck kodunun önünde yer ayıramazsınız.

Bir sonraki sorun, Nonu işlerken listeyi küçültmek için bırakmamız gerek ve daha önce olduğumuz yere geri dönmemiz gerekiyor. Ancak {ve }sadece tüm listeyi atlardı.

Bu yüzden Chuck’a dinamik olarak bazı kodlar yazmamız gerekiyor. Aslında, her liste elemanı işu şekildedir:

[1 <Code A> i <Code B>]

1listeyi işlemeyi bıraktığımız yeri belirtmek için sıfıra ayarlayabileceğimiz bir işaretleyicidir. Amacı yakalamak {ve }sadece kodu ve kodunu geçecek olan i. Bu değeri, işlem sırasında listenin sonunda olup olmadığımızı kontrol etmek için de kullanırız, bu yüzden değilken, bu olur 1ve şartlı ?kontrol Chuck'a geçer. Code ABu durumu ele almak ve buna göre IP'yi Brian'a taşımak için kullanılır.

Şimdi azaldığımızda , sıfır iolup olmadığını kontrol etmemiz gerekiyor i. Olmasa da ?kontrolü tekrar değiştirecek, yani Code Bbununla başa çıkacak .



@cardboard_box Güzel!
mbomb007

15

Python 3 ile yazılmış HPR ( TheNumberOne tarafından Cracked )

HPR (ad hiçbir şey ifade etmiyor), tam sayıların listelerini işlemek için kullanılan bir dildir. Minimalist , son derece sınırlı ve "yapay" kısıtlamalardan arınmış şekilde tasarlanmıştır . HPR'de programlama yapmak zordur, çünkü tercümanı size bağırmaktan alıkoyacak bir bulmacayı çözmek zorunda kalırsınız, ancak bir programı faydalı bir şey yapmak zorlaştırır. HPR'nin listenin en büyük üçüncü elemanını hesaplamaktan çok daha ilginç bir şey yapıp yapamayacağını bilmiyorum.

Dil özellikleri

Bir HPR programı, sırasız yinelenmeyen, negatif olmayan bir tamsayı kümesi ve negatif olmayan bir tamsayı listesi olan bir ortamda çalıştırılır . Başlangıçta, ortam yalnızca girdi listesini içerir (tercüman sizin için ayrıştırır). Çevreyi değiştiren üç komut ve iki "kontrol akışı" operatörü vardır:

  • *boş olmayan her listenin ilk öğesini ortamdan kaldırır ve ortama yerleştirir. Boş listeler etkilenmez. Örneğin, dönüştürür

    {4,1,[0,2],[1,3],[]} -> {4,1,0,[2],[3],[]}
    
  • -ortamdaki tüm sayıları azaltır ve ardından negatif öğeleri kaldırır. Örneğin, dönüştürür

    {4,2,0,[0,2],[4,4,4]} -> {3,1,[0,2],[4,4,4]}
    
  • $ortamdaki her listeyi bir adım sola döndürür. Örneğin, dönüştürür

    {4,1,[0,2],[3,4,1]} -> {4,1,[2,0],[4,1,3]}
    
  • !(A)(B), programlar nerede Ave nerede B, temelde bir whiledöngüdür. A"Test" Bboş bir ortamda sonuçlanıncaya kadar "eylem" gerçekleştirir . Bu sonsuz bir döngü üretebilir.
  • #(A)(B)programlar nerede Ave nerede , geçerli ortama Buygulanır Ave Bsonuçların simetrik farkını alır.

Komutlar soldan sağa doğru yürütülür. Sonunda, ortamın büyüklüğü unary olarak yazdırılır.

Çevirmen

Bu yorumlayıcı ?, çevreyi değiştirmeden basan hata ayıklama komutunu içerir. Göreve herhangi bir çözümde görünmemelidir. Dışındaki herhangi bir karakter *-$!#()?basitçe yoksayılır, bu nedenle yorumları doğrudan koda yazabilirsiniz. Son olarak, tercüman, deyimi !(A)(#(A)())" Asonuç artık değişinceye kadar gerçekleştir" olarak tanır ve ekstra hız için optimize eder (çözümümün son test vakasında bir saatten daha az bir sürede bitmesini sağlamak için gerekli).

import sys

def parse(prog):
    "Parse a prefix of a string into an AST. Return it and the remaining input."
    ret = []
    while prog:
        if prog[0] in "#!":
            sub1, prog1 = parse(prog[2:])
            sub2, prog2 = parse(prog1[1:])
            ret += [prog[0],sub1,sub2]
            prog = prog2
        elif prog[0] == ')':
            prog = prog[1:]
            break
        else:
            ret += [prog[0]]
            prog = prog[1:]
    return ret, prog

def intp(ast, L_env, N_env):
    "Interpret the AST on an environment, return the resulting environment."
    ptr = 0
    while ptr < len(ast):
        cmd = ast[ptr]
        if cmd == '*':
            N_env = N_env | set(L[0] for L in L_env if L)
            L_env = set(L[1:] for L in L_env)
            ptr += 1
        elif cmd == '-':
            N_env = set(N-1 for N in N_env if N>0)
            ptr += 1
        elif cmd == '$':
            L_env = set(L[1:]+L[:1] for L in L_env)
            ptr += 1
        elif cmd == '!':
            # Speed optimization
            cond = ast[ptr+2]
            if cond == ['#', ast[ptr+1], []]:
                L_next, N_next = intp(ast[ptr+1], L_env, N_env)
                while L_next != L_env or N_next != N_env:
                    L_env, N_env = L_next, N_next
                    L_next, N_next = intp(ast[ptr+1], L_env, N_env)
            else:
                while True:
                    L_test, N_test = intp(cond, L_env, N_env)
                    if not L_test and not N_test:
                        break
                    L_env, N_env = intp(ast[ptr+1], L_env, N_env)
            ptr += 3
        elif cmd == '#':
            L_env1, N_env1 = intp(ast[ptr+1], L_env, N_env)
            L_env2, N_env2 = intp(ast[ptr+2], L_env, N_env)
            L_env = L_env1 ^ L_env2
            N_env = N_env1 ^ N_env2
            ptr += 3
        elif cmd == '?':
            print(L_env | N_env)
            ptr += 1
        else:
            ptr += 1
    return L_env, N_env

def main(p, L):
    "Run the program on the input, return the output."
    # Parse the input list
    L = ''.join(c for c in L if c in "01")
    while "00" in L:
        L = L.replace("00","0")
    L = [-2] + [i for i in range(len(L)-1) if L[i:i+2] == "10"]
    L = tuple(b-a-1 for (a,b) in zip(L, L[1:]))
    # Parse the program
    ast = parse(p)[0]
    L_env, N_env = intp(ast, set([L]), set())
    return '1'*(len(L_env) + len(N_env))

if __name__ == "__main__":
    filename = sys.argv[1]
    f = open(filename, 'r')
    prog = f.read()
    f.close()
    L = input()
    print(main(prog, L))

Çözümüm

Referans çözümüm 484 bayt uzunluğunda, TheNumberOne'ın 3271 baytlık programına göre oldukça kısa. Bu, büyük olasılıkla HPR'de programlama için geliştirilen sofistike ve harika makro sistemi TheNumberOne nedeniyledir. Her iki programda da ana fikir benzer:

  1. Bir listenin maksimum elemanının nasıl üretileceğini öğrenin.
  2. Maksimum öğeyi kaldırmak için, ilk öğe maksimum değere eşit olana kadar listeyi çevirin ve ardından kaydırın.
  3. En fazla iki kez kaldırın, ardından yeni en fazla elemanı yazdırın.

Ancak, söyleyebileceğim kadarıyla, tam uygulama detayları oldukça farklı. İşte benim çözümüm:

!($)(!(-)(#(-)())#(!(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))(#(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))())#(-)(#(!(-)(#(-)()))()))(*)#(!(-)(#(-)()))())*!(-)(#(-)())!($)(!(-)(#(-)())#(!(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))(#(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))())#(-)(#(!(-)(#(-)()))()))(*)#(!(-)(#(-)()))())*!(-)(#(-)())!(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))(#(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))())-#(!(-)(#(-)()))()

Ve işte onu üreten yorumlanmış Python programı (burada hiçbir şey fantezi değil, sadece tüm tekrarlardan kurtulmak için basit dize manipülasyonu):

# No numbers in the environment
no_nums = "#(-)()"
# No non-empty lists in the environment
no_lists = "#(*)()"
# Remove all numbers from the environment
del_nums = "!(-)(" + no_nums + ")"
# Remove all lists from the environment
del_lists = "#(" + del_nums + ")()"
# Splat the list to the environment:
#  pop the list until it's empty and delete the empty list,
#  then take symmetric difference with all numbers removed
splat = "#(!(*)(" + no_lists + ")" + del_lists + ")(" + del_nums + ")"
# Put into the environment all numbers up to list maximum:
#  decrement and splat until a fixed point is reached.
#  Without the speed optimization, this is very slow if the list elements are large.
splat_upto = "!(-" + splat + ")(#(-" + splat + ")())"
# Copy maximum element to environment:
#  take all elements up to maximum,
#  then take symmetric difference of decrement and list deletion
copy_max = splat_upto + "#(-)(" + del_lists + ")"
# Delete maximum element from list:
#  rotate until first element is maximal, then pop and delete it
del_max = "!($)(" + del_nums + "#(" + copy_max + ")(*)" + del_lists + ")*" + del_nums
# Full program:
#  remove the maximum twice, then produce all numbers up to maximum,
#  then decrement and remove lists. The environment will contain exactly
#  the integers from 0 to third largest - 1, and their number is printed.
main = del_max + del_max + splat_upto + "-" + del_lists
print(main)


@TheNumberOne Çözümümü ekledim.
Zgarb

12

TKDYNS (Ejderhayı Öldürmek İçin Kılıca İhtiyacınız Var) - Martin Büttner

EDIT: Çözümümü ve açıklamayı ana yazının altına ekledim.

Arka fon

Bu dilde, korkunç bir ejderha öldürmekle görevlendirilmiş yiğit bir savaşçının kontrolünü ele geçirirsiniz. Ejderha, tehlike ve tehlikelerle dolu bir yeraltı labirentinde yaşıyor ve şimdiye kadar, hiç kimse onu haritaya sokup hayatta kalmayı başaramadı. Bu, ejderhaya giden yolda zifiri karanlıkta, sizi yönlendirecek sezgiden ve cesaretten başka hiçbir şey olmadan gitmeniz gerektiği anlamına gelir.

...

Pek iyi değil. Yanınıza neredeyse sınırsız miktarda harcanabilir köle kaynağı getirdiniz ve güvenli rotayı bulmak için önünüze çıkmak istiyorlar. Maalesef, hepsi iki kısa kalas kadar kalınlar ve tam olarak ne yapmaları gerektiğini söylediklerini yapacaklar. Kölelerinin doğru yolu keşfetmesini sağlamak için akıllıca bir yöntem bulmak sana kalmış.

Biraz daha detay

Ejderhanın inişi 10x10 ızgara şeklini alır. Izgaradaki bazı bitişik noktalar arasında, dar bir geçit vardır; diğerleri arasında derin bir uçurum ve kesin bir ölüm var. 4x4 ızgarası için örnek bir düzen aşağıdaki gibi olabilir:

 0---1   2---3
     |   |   |
 4---5---6   7
 |           |
 8   9--10  11
     |       |
12--13--14--15

Her zaman bir noktadan diğer noktalara ulaşmanın bir yolu olduğunu biliyorsunuz, ancak bundan daha fazlası size açıklanmadı.

Ejderhayı başarılı bir şekilde yenmek için, önce sihirli bir ejderha avlama bıçağı oluşturmak için bir araya getirebileceğiniz bazı eşyaları toplamanız gerekir. Uygun bir şekilde, bu silahın tüm parçaları ejderhanın inine dağılmış durumda. Onları toplamalısın.

Büküm, silahın her bir parçasının bubi tuzağı altında tutulmuş olmasıdır. Her biri toplandığında, yürüyüş yollarının düzeni değişir. Daha önce güvenli yollar şimdi kesin ölümlere ve bunun tersi yol açabilir.

Komutları

Sadece 5 geçerli komut var.

  • < - Sola bir adım at

  • > - Sağa bir adım atın

  • ^ - Yukarı doğru bir adım atın

  • v - Aşağı doğru bir adım atın

  • c- Bulunduğunuz konumda etrafta yatmakta olan eşyaları toplayın. Mevcut öğeler varsa, inin düzeni değişir. Yukarıdaki gibi sıralarda numaralandırılmış konumlarda, 10 pozisyonunuzu alın. Tercümana kodlanmış 10 düzen vardır ve düzen karşılık gelen şekle değişir. Örneğin, 13 konumdaysanız, düzenlayouts[3]

Yorumlayıcıda göründükleri düzenler, tam sayılara aşağıdaki şekilde kodlanmıştır:

  • Boş düzen sıfıra kodlanmış.

  • Mizanpajdaki her kenar için, xbirleştiği iki konumdan daha küçük olalım .

    • Adım yatay 2^(2*x)ise, kodlamaya ekleyin (bu XOR değil, gücüdür)

    • Adım dikey 2^(2*x + 1)ise, kodlamaya ekleyin .

Yürütme akışı

Tercüman, bir kaynak dosyanın adı ile komut satırı argümanı olarak çalıştırılır.

Tercüman çalıştırıldığında, kullanıcıdan bir görev yapmasını ister. Bu girdi soruda açıklanan biçimde olmalı ve silah bileşenlerinin inindeki yerleri belirler. Spesifik olarak, her bir giriş tamsayısı, modulo 100 alınır ve indeki karşılık gelen yere yerleştirilir.

Her kaynak program, her biri yukarıdaki 5 geçerli karakterden oluşan bir diziden oluşan birkaç satırdan oluşur. Bu çizgiler kölelerini temsil ediyor. Siz, savaşçı, güvenli olduğu bilinen bir dizi eylemi takip edin. Başlangıçta, inine ilişkin hiçbir şey bilmiyorsunuz, bu yüzden bu dizi boştur. Her minionu sırayla alarak, 0 konumundan başlayarak aşağıdakiler gerçekleştirilir:

  • Minion'a, güvenli olduğu bilinen tüm eylemleri gerçekleştirmesi ve ardından kendi kod satırındaki eylemleri gerçekleştirmesi talimatı verilir.

    • Eğer köle herhangi bir noktada ölürse, bu size bildirilir ve ine ilk konfigürasyonuna döner. Tüm eşyalar değiştirilir ve yürüyüş yolları başlangıç ​​pozisyonlarına döner.

    • Bunun yerine, köle hayatta kalırsa, yine de buharlaşırsınız - sonuçta bu sadece bir köleliktir. Önceden olduğu gibi, bu durum inin ilk durumuna sıfırlanmasını tetikler, ancak bu sefer, kölelerinin kod satırından güvenli işlemler olarak bilinen işlemlerin sırasına eylemler eklersiniz.

Tüm köleler tükendiğinde, siz, savaşçı, güvenli olduğu bilinen tüm eylemleri gerçekleştirirsiniz, tekrar 0 konumundan başlayabilirsiniz. İki olası sonuç vardır:

  • Silahın tüm parçalarını topluyorsunuz - bu durumda ejderhayı başarıyla öldürüyorsunuz ve heyecan verici bir zafer mesajı çıkıyor. Bu zafer mesajı, diğer karakterlerin yanı sıra, girdi olarak sağlanan üçüncü en yüksek sayıyı içerecek nolanları içerecektir n.

  • Silahın bazı parçalarını toplayamadınız - bu durumda, ejderha yaşıyor ve arayışınızda başarısız oldunuz.

Tercüman kodu (Python 2)

import collections
import copy
import sys

size = 10
layouts = [108705550239329248440770931020110627243913363144548922111951,108386637020100924277694952798729434993885646706222210602969,133885860318189115027934177821170081234850573770998325845482,102397795295522647918061101991513921833376565032742993744791,131948019244359669407266662537098175265242405785636894694611,127512068876349726396523358265982765442984953916545984706958,106817519055019354200334114020150263381328246524221867629943,33472343358375525802921815863230485208221126168622186265959,133909781123963725874096031069972704024813281938330035579187,132244654022332695610020359820518831299843076834682749020986]

class Interpreter(object):

    def __init__(self, source_file):
        self.source_filename = source_file
        self.layout = layouts[0]
        self.position = 0
        self.ingredients = []
        self.quest_items = {}
        self.attempts = collections.deque()

        self.safe_position = 0
        self.safe_ingredients = []
        self.safe_quest_items = {}
        self.safe_layout = layouts[0]

    def get_input(self):
        s = raw_input("Which quest would you like to embark on today?")
        ind = s.find('00')
        s = s[:ind]
        items = map(len, s.split('0'))
        for item in items:
            if item not in self.safe_quest_items:
                self.safe_quest_items[item] = 1
            else:
                self.safe_quest_items[item] += 1

    def parse_attempts(self):
        with open(self.source_filename, 'r') as source:
            for line in source:
                self.attempts.append(line.strip())

    def enc(self, x, y):
        x, y = min(x, y), max(x, y)
        if x < 0:
            return 0
        if y == x + 1:
            return 1 << (2*x)
        elif y == x + size:
            return 1 << (2*x + 1)
        else:
            return 0

    def exec_command(self, char):
        if char == '<':
            if self.enc(self.position, self.position-1) & self.layout:
                self.position -= 1
            else:
                return False
        elif char == '>':
            if self.enc(self.position, self.position+1) & self.layout:
                self.position += 1
            else:
                return False
        elif char == '^':
            if self.enc(self.position, self.position-size) & self.layout:
                self.position -= size
            else:
                return False
        elif char == 'v':
            if self.enc(self.position, self.position+size) & self.layout:
                self.position += size
            else:
                return False
        elif char == 'c':
            for item in xrange(self.position, 10**6, size*size):
                if item in self.quest_items:
                    self.ingredients += ([item] * self.quest_items.pop(item))
                    self.ingredients.sort()
                    self.layout = layouts[self.position % 10]
        else:
            raise ValueError

        return True

    def run_minion(self):
        minion = self.attempts.popleft()
        self.position = self.safe_position
        self.ingredients = copy.copy(self.safe_ingredients)
        self.quest_items = copy.copy(self.safe_quest_items)
        self.layout = self.safe_layout
        dead = False

        for cmd in minion:
            if not self.exec_command(cmd):
                dead = True

        if not dead:
            self.safe_position = self.position
            self.safe_ingredients = copy.copy(self.ingredients)
            self.safe_quest_items = copy.copy(self.quest_items)
            self.safe_layout = self.layout

    def process_minions(self):
        while self.attempts:
            self.run_minion()

    def final_run(self):
        if len(self.safe_quest_items) == 0:
            print "You killed the dragon" + "!!1" * self.safe_ingredients[-3]
        else:
            print "The dragon lives on. Better luck next time..."

    def interpret(self):
        self.get_input()
        self.parse_attempts()
        self.process_minions()
        self.final_run()

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print "Wrong number of arguments"
    else:
        test = Interpreter(sys.argv[1])
        test.interpret()

Bol şans, yiğit savaşçı.

Benim çözümüm ve açıklamam

İşte sorunu çözmek için kaynak kodunu üreten bir Python betiği. İlgi çeken, Martin'in nihai kaynak kodu, senaryomun ürettiği koddan yaklaşık 5 kat daha küçük. Öte yandan, kodu oluşturma betiğim Martin Mathematica programından 15 kat daha küçük ...

size = 10
layouts = [108705550239329248440770931020110627243913363144548922111951,108386637020100924277694952798729434993885646706222210602969,133885860318189115027934177821170081234850573770998325845482,102397795295522647918061101991513921833376565032742993744791,131948019244359669407266662537098175265242405785636894694611,127512068876349726396523358265982765442984953916545984706958,106817519055019354200334114020150263381328246524221867629943,33472343358375525802921815863230485208221126168622186265959,133909781123963725874096031069972704024813281938330035579187,132244654022332695610020359820518831299843076834682749020986]

def enc(edge):
    x,y = min(edge), max(edge)
    if x < 0:
        return 0
    if y == x + 1:
        return 1 << (2*x)
    elif y == x + size:
        return 1 << (2*x + 1)

def path(x, y, tree):
    stack = [(x,'')]
    while stack[-1][0] != y:
        vertex, path = stack.pop()
        if (enc((vertex, vertex+1))&tree) and ((not path) or path[-1] != '<'):
            stack.append((vertex+1, path+'>'))
        if (enc((vertex, vertex-1))&tree) and ((not path) or path[-1] != '>'):
            stack.append((vertex-1, path+'<'))
        if (enc((vertex, vertex+size))&tree) and ((not path) or path[-1] != '^'):
            stack.append((vertex+size, path+'v'))
        if (enc((vertex, vertex-size))&tree) and ((not path) or path[-1] != 'v'):
            stack.append((vertex-size, path+'^'))
    return stack[-1][1]

def reverse(path):
    rev = ''
    for i in xrange(len(path)-1, -1 ,-1):
        if path[i] == '<':
            rev += '>'
        if path[i] == '>':
            rev += '<'
        if path[i] == 'v':
            rev += '^'
        if path[i] == '^':
            rev += 'v'
    return rev

def assert_at(x, tree):
    path_ul = path(x, 0, tree)
    path_dr = path(x, size*size - 1, tree)
    return path_ul + reverse(path_ul) + path_dr + reverse(path_dr)

def safe_path(x, y, tree):
    return assert_at(x, tree) + path(x, y, tree)

with open('source.txt', 'w') as f:
    for x in xrange(size*size - 1):
        for tree in layouts:
            f.write(safe_path(x, x+1, tree) + 'c\n')

Basit yapı

Bu 10'luk gruplar halinde gelip kaynak kodunun 990 satırları, ilk 10 satır tüm pozisyondan bir minion taşımak istediğinizde talimatlar içerir üretir 0konuma 1her olası bir düzen için bir set - ve sonra bir öğeyi toplamak. Önümüzdeki 10 satır tüm pozisyondan bir minion taşımak istediğinizde talimatları ihtiva 1pozisyona 2ve ardından bir öğeyi toplamak. Ve böyle devam eder ... Bu yollar pathkomut dosyasındaki işlevle hesaplanır - yalnızca basit bir derinlik-ilk araması yapar.

Her 10 kişilik grupta kesin olarak bir minyonun başarılı olmasını sağlayabilirsek, sorunu çözmüş olacağız.

Yaklaşımla ilgili sorun

Her zaman kesin olarak, 10'lu gruptan bir minyonun başarılı olması - örneğin, bir pozisyondan pozisyona 0geçmek için tasarlanan bir minyonun 1yanlışlıkla ( 1pozisyonlardaki 2benzerlikler nedeniyle) pozisyondan pozisyona hareket etmekte başarılı olabileceği ve yanlış hesaplama, potansiyel olarak başarısızlığa neden olacak şekilde ilerler.

Nasıl düzeltilir

Kullandığım düzeltme aşağıdaki gibiydi:

Pozisyondan almaya çalışırken her minion için niçin n+1öncelikle onu pozisyondan yürümeye yapmak npozisyona 0pozisyondan sonra tekrar (sol üst köşe) ve npozisyona 99tekrar (sağ alt köşe) ve. Bu talimatlar yalnızca güvenli bir şekilde pozisyondan gerçekleştirilebilir n- başka bir başlangıç ​​pozisyonu ve minion kenardan yürüyecektir.

Bu ilave talimatlar bu nedenle, kölelerinin yanlışlıkla istemedikleri bir yere gitmelerini önler ve bu da her 10 grubun birinden birinin başarılı olmasını sağlar. Olmasını beklediğiniz köleliğin ille de olmadığına dikkat edin - düzen 0'da olduğuna inanan köleliğin, gerçekten düzen 7'de olduğumuzda bile başarılı olabileceği - ancak her durumda, Şimdi pozisyonun değişmesi, gruptaki diğer bütün kölelerin mutlaka öleceği anlamına geliyor. Bu fazladan adımlar, assert_atfonksiyon tarafından hesaplanır ve fonksiyon, safe_pathbu fazladan adımların sıradan yolla birleştirildiği bir yol döndürür.


1
Çatlak. Bu çok eğlenceliydi, ama bence "programlama diliniz sadece bir görevi yerine getirmeli" kuralıyla ilgili bir sorun ortaya çıkardı, çünkü bulmacanın kırılması bu programlama görevini çözme ile ilgisi yoktu. ;)
Martin Ender

Bu cevabı temel olarak hazırladım çünkü sorunun var olduğunu fark ettim - ve birinin yerine gerçekten zor bir hesaplama problemi kullanmasını engelleyen bir şey yok gibi görünüyor. Kripto yok yasağı keyfi dar gözüküyor ...
Sam Cappleman-Lynes

doğru. Sanırım bu yüzden popülerlik yarışması. Eğer sorun daha fazla hesaplama niteliğindeyse ve gerçekten de gerçekten zor olan uygun (potansiyel olarak tamamlanmış) bir dilin cevabını verilen oylar kadar güzel bir hikayeye sarılmamışsa.
Martin Ender

İlgilendiğim çözümü ekledi. Ayrıca ilgi için, bulmacayı başlangıçta 1000x1000'lik bir ızgara göz önünde bulundurarak tasarladım, ancak daha küçük boyut için seçtiğim ~ 600000 basamaklı sayılara kodlanmış düzenlere sahip olmama konusunda.
Sam Cappleman-Lynes

8

Firetype, Martin Büttner tarafından Cracked

BF ve CJam'ın gerçekten garip bir karışımı. Ve başka ne biliyor kim! Bunun kolay olacağından eminim, ama yine de eğlenceliydi. Bilginize, adı Final Fantasy Type-0'dan Vermillion Fire .

NOT : Lütfen bu tanımdaki herhangi bir belirsizlik yüzünden beni bağışlayın. Ben en iyi yazar değilim ...: O

Martin bunu çok çabuk çözdü! Bu sorunu çözmek için özgün programımdı:

_
,
^
~
+
|
|
-
%
+
_
+
=











`
~
+
|
%

_
=

\
@
-
-
!
<
>
>
>

_
+
.
<
-
`
~
~
+
|
|
-
#
%

Sözdizimi

Bir Firetype betiği temelde satırların bir listesidir. Her satırın ilk karakteri çalıştırılacak komuttur. Boş satırlar temel olarak NOP'lardır.

semantik

Bir dizi tamsayı ve bir işaretçi var (BF düşünün). Dizinin üzerine sola ve sağa hareket ettirebilir veya elemanları "itebilir".

itme

Bir elementi "bastırdığınızda" ve dizinin sonunda olduğunuzda, sonuna ekstra bir eleman eklenecektir. Sonunda değilseniz, bir sonraki eleman geçersiz kılınır. Ne olursa olsun, işaretçi her zaman artırılır.

Komutları

_

Dizinin üzerine bir sıfır itin.

+

Geçerli işaretçideki öğeyi artır.

-

Geçerli işaretçideki öğeyi azalt.

*

Öğeyi geçerli işaretleyicide ikiye katlayın.

/

Öğeyi geçerli işaretçide yarıya indir.

%

Öğeyi geçerli işaretçiye götür ve o kadar çok çizgiyi atla ve işaretçiyi sola doğru kaydır. Değer negatifse, bunun yerine geriye doğru atlayın.

=

Öğeyi geçerli göstergede al ve o satıra + 1 atla. Örneğin, eğer geçerli eleman ise 0, bu satır atlayacaktır 1. Bu ayrıca işaretçiyi sola doğru hareket ettirir.

,

Standart girişten bir karakter okuyun ve ASCII değerine basın.

^

Öğeyi geçerli göstergeye götür, bir karakter için ASCII değeri olarak yorumla ve bir tam sayıya dönüştür. Örneğin, mevcut değer 49 (ASCII değeri 1) ise, geçerli göstergedeki öğe tamsayıya ayarlanır 1.

.

Geçerli numarayı ekrana yazın.

!

Öğeyi geçerli işaretçiye alın ve bir sonraki satırı birçok kez tekrarlayın. Ayrıca işaretçiyi sola kaydırır.

<

İşaretçiyi sola hareket ettirin. Zaten başlangıçtaysanız, bir hata atılır.

>

İşaretçiyi sağa hareket ettirin. Zaten sonunda iseniz, bir hata atılır.

~

Geçerli eleman sıfır değilse, ile değiştirin 0; Aksi takdirde, ile değiştirin 1.

|

Geçerli öğeyi kare içine alın.

@

Geçerli öğeyi dizinin uzunluğuna ayarlayın.

`

Geçerli öğeyi çoğalt.

\

Öğeleri imlecin içindeki ve yanındaki sıralayın.

#

Geçerli öğeyi olumsuzlayın.

Çevirmen

Ayrıca Github'da da mevcuttur .

#!/usr/bin/env python

# The FireType interpreter.
# Runs under Python 2 and 3.
import sys

class Array(object):
    def __init__(self):
        self.array = []
        self.ptr = 0

    def push_zero(self):
        if self.ptr == len(self.array):
            self.array.append(0)
        else:
            self.array[self.ptr] = 0
        self.ptr += 1

    def left(self):
        self.ptr -= 1
        assert self.ptr >= 0 and self.array, 'pointer underflow (at %d)' % i

    def right(self):
        self.ptr += 1
        assert self.ptr <= len(self.array), 'pointer overflow (at %d)' % i

    def sort(self):
        lhs = self.array[:self.ptr-1]
        rhs = self.array[self.ptr-1:]
        lhs.sort()
        lhs.reverse()
        self.array = lhs + rhs

    def __call__(self, *args):
        args = list(args)
        assert self.array, 'out-of-bounds (at %d)' % i
        if not args:
            return self.array[self.ptr-1]
        self.array[self.ptr-1] = args.pop()
        assert not args

    def __len__(self):
        return len(self.array)

    def __str__(self):
        return 'Array(array=%s, ptr=%s)' % (self.array, self.ptr)

    def __repr__(self):
        return 'Array(array=%r, ptr=%r)' % (self.array, self.ptr)

def execute(lines):
    global i, array
    i = 0
    array = Array()
    rep = 0
    while i < len(lines):
        line = lines[i]
        if not line:
            i += 1
            continue
        line = line[0]
        if line == '_':
            array.push_zero()
        elif line == '+':
            array(array() + 1)
        elif line == '-':
            array(array() - 1)
        elif line == '*':
            array(array() * 2)
        elif line == '/':
            array(int(array() / 2))
        elif line == '%':
            i += array()
            array.left()
        elif line == '=':
            i = array()-1
            array.left()
        elif line == ',':
            array.push_zero()
            array(ord(sys.stdin.read(1)))
        elif line == '.':
            sys.stdout.write(str(array()))
        elif line == '!':
            rep = array()
            array.left()
            i += 1
        elif line == '<':
            array.left()
        elif line == '>':
            array.right()
        elif line == '^':
            array(int(chr(array())))
        elif line == '~':
            array(int(not array()))
        elif line == '|':
            array(array() ** 2)
        elif line == '@':
            array(len(array))
        elif line == '`':
            top = array()
            array.push_zero()
            array(top)
        elif line == '\\':
            array.sort()
        elif line == '#':
            array(-array())

        if rep:
            rep -= 1
        else:
            i += 1

def main(args):
    try:
        _, path = args
    except ValueError:
        sys.exit('usage: %s <file to run, - for stdin>')

    if path == '-':
        data = sys.stdin.read()
    else:
        with open(path) as f:
            data = f.read()

    try:
        execute(data.split('\n'))
    except:
        print('ERROR!')
        print('Array was %r' % array)
        print('Re-raising error...')
        raise

if __name__ == '__main__':
    main(sys.argv)

Dizinin alt sınırı için iddianın buggy olduğunu düşünüyorum. self.ptr-1Erişim için kullandığınızdan , muhtemelen kontrol self.ptr>0etmemelisiniz >=0. (Bu herhangi bir geçerli programı geçersiz kılmamalı, ancak bazı programların yanlışlıkla çalışması gereken işleri yapmasına neden olabilir.)
Martin Ender

Bir şey daha var: Kodun =değeri ayarladığını array() - 1söylüyor, belgelere göre +1?
Martin Ender

Çatlak. (Tercümanın normatif olduğunu varsayalım, açıklamayı değil.)
Martin Ender

@ MartinBüttner Dang, düşündüğümden daha hızlıydı! : OI bahsettiğiniz doktor sorunlarını düzelttim.
kirbyfan64sos

7

Acc !! (kasa)

Baack ...

görüntü tanımını buraya girin

... ve umarım kesinlikle daha fazla delik açmaz.

Ben zaten Acc okudum ! Spec. Acc nasıl ! farklı?

In Acc !! , döngü değişkenleri, döngüden çıktığında kapsam dışına çıkar. Bunları yalnızca döngünün içinde kullanabilirsiniz. Dışında, "ad tanımlanmadı" hatası alırsınız. Bu değişiklik dışında, diller aynıdır.

tablolar

Komutlar satır satır ayrıştırılır. Üç tür komut vardır:

  1. Count <var> while <cond>

Sayımlar <var>kadar 0 sürece gelen <cond>, sıfır olmayan bir C ++ eşdeğerdir for(int <var>=0; <cond>; <var>++). Döngü sayacı herhangi bir tek küçük harf olabilir. Koşul, mutlaka döngü değişkenini içermeyen, herhangi bir ifade olabilir. Döngü, koşulun değeri 0 olduğunda durur.

Döngüler K & R tarzı kaşlı ayraçlar gerektirir (özellikle, Stroustrup varyantı ):

Count i while i-5 {
 ...
}

Yukarıda bahsedildiği gibi, döngü değişkenleri sadece döngülerinin içinde bulunur ; daha sonra bunlara referans vermeye çalışmak bir hataya neden olur.

  1. Write <charcode>

Verilen ASCII / Unicode değerine sahip tek bir karakteri stdout'a verir. Karakter kodu herhangi bir ifade olabilir.

  1. ifade

Tek başına duran herhangi bir ifade değerlendirilir ve akümülatöre (olarak erişilebilir _) geri atanır . Dolayısıyla, örneğin, 3akümülatörü 3'e ayarlayan bir ifadedir; _ + 1akümülatörü arttırır; ve _ * Nbir karakter okur ve akümülatörü karakter koduyla çarpar.

Not: akümülatör doğrudan atanabilecek tek değişkendir; Döngü değişkenleri ve Nhesaplamalarda kullanılabilir ancak değiştirilmez.

Akümülatör başlangıçta 0'dır.

İfade

Bir ifade, tamsayı değişmezleri, toplayıcı için loop değişkenleri ( a-z) _ve Nbir karakteri okuyup her kullanıldığında karakter kodunu değerlendiren özel değeri içerebilir. Not: bu, her karakteri okumak için yalnızca bir kez çekim yapabileceğiniz anlamına gelir; bir dahaki Nsefere bir dahaki sefere okuyacaksın.

Operatörler:

  • +, ilave
  • -, çıkarma; tekli olumsuzlama
  • *, çarpma işlemi
  • /, tamsayı bölümü
  • %, modulo
  • ^üstel

Parantez, işlemlerin önceliğini zorlamak için kullanılabilir. Bir ifadedeki herhangi bir karakter, bir sözdizimi hatasıdır.

Boşluk ve yorumlar

Lider ve takip eden boşluk ve boş satırlar dikkate alınmaz. Döngü başlıklarındaki boşluk, tam olarak gösterildiği gibi olmalıdır, ayrıca döngü başlığı ve açılış küme parantezi arasında tek bir boşluk bırakılmalıdır. İfadelerin içindeki boşluklar isteğe bağlıdır.

# tek satırlı bir yorum başlatır.

Giriş çıkış

Acc !! giriş olarak tek bir karakter satırı bekler. Her giriş karakteri sırayla alınabilir ve karakter kodu kullanılarak işlenir N. Satırın son karakterini okumaya çalışmak bir hataya neden olur. Bir karakter, karakter kodunu ifadeye geçirerek çıkarılabilir Write.

tercüman

Tercüman (Python 3 ile yazılmıştır) Acc !! Python içine kodlayın ve execs.

import re, sys

def main():
    if len(sys.argv) != 2:
        print("Please supply a filename on the command line.", file=sys.stderr)
        return
    codeFile = sys.argv[1]
    with open(codeFile) as f:
        code = f.readlines()
    code = translate(code)
    exec(code, {"inputStream": (ord(char) for char in input())})

def translate(accCode):
    indent = 0
    loopVars = []
    pyCode = ["_ = 0"]
    for lineNum, line in enumerate(accCode):
        if "#" in line:
            # Strip comments
            line = line[:line.index("#")]
        line = line.strip()
        if not line:
            continue
        lineNum += 1
        if line == "}":
            if indent:
                loopVar = loopVars.pop()
                pyCode.append(" "*indent + loopVar + " += 1")
                indent -= 1
                pyCode.append(" "*indent + "del " + loopVar)
            else:
                raise SyntaxError("Line %d: unmatched }" % lineNum)
        else:
            m = re.fullmatch(r"Count ([a-z]) while (.+) \{", line)
            if m:
                expression = validateExpression(m.group(2))
                if expression:
                    loopVar = m.group(1)
                    pyCode.append(" "*indent + loopVar + " = 0")
                    pyCode.append(" "*indent + "while " + expression + ":")
                    indent += 1
                    loopVars.append(loopVar)
                else:
                    raise SyntaxError("Line %d: invalid expression " % lineNum
                                      + m.group(2))
            else:
                m = re.fullmatch(r"Write (.+)", line)
                if m:
                    expression = validateExpression(m.group(1))
                    if expression:
                        pyCode.append(" "*indent
                                      + "print(chr(%s), end='')" % expression)
                    else:
                        raise SyntaxError("Line %d: invalid expression "
                                          % lineNum
                                          + m.group(1))
                else:
                    expression = validateExpression(line)
                    if expression:
                        pyCode.append(" "*indent + "_ = " + expression)
                    else:
                        raise SyntaxError("Line %d: invalid statement "
                                          % lineNum
                                          + line)
    return "\n".join(pyCode)

def validateExpression(expr):
    "Translates expr to Python expression or returns None if invalid."
    expr = expr.strip()
    if re.search(r"[^ 0-9a-z_N()*/%^+-]", expr):
        # Expression contains invalid characters
        return None
    elif re.search(r"[a-zN_]\w+", expr):
        # Expression contains multiple letters or underscores in a row
        return None
    else:
        # Not going to check validity of all identifiers or nesting of parens--
        # let the Python code throw an error if problems arise there
        # Replace short operators with their Python versions
        expr = expr.replace("^", "**")
        expr = expr.replace("/", "//")
        # Replace N with a call to get the next input character
        expr = expr.replace("N", "inputStream.send(None)")
        return expr

if __name__ == "__main__":
    main()

Çözüm

Orijinal Acc'in çöküşü ! döngülerinin dışında erişilebilir olmaya devam eden döngü değişkenleriydi. Bu, akümülatörün tasarruf kopyalarını sağladı; bu da çözümü çok kolaylaştırdı.

Burada, bu döngü deliği olmadan (üzgünüm), sadece depolayacak akümülatörümüz var. Görevi çözmek için, dört tane rasgele büyük değer kaydetmemiz gerekiyor. 1 Çözüm: bitlerini serpiştirin ve elde edilen kombinasyon numarasını akümülatörde saklayın. Örneğin, 6437 bir akümülatör değeri şu verileri depolar (en düşük dereceli bit'i tek bitlik bayrak olarak kullanarak):

1100100100101  Binary representation of accumulator
321032103210F  Key

The flag is 1 and the four numbers are
Number 0: 010 = 2
Number 1: 001 = 1
Number 2: 100 = 4
Number 3: 110 = 6

Akümülatörü 2, mod 2 uygun gücüne bölerek herhangi bir sayının herhangi bir bitine erişebiliriz. Bu, ayrı ayrı bitlerin ayarlanmasına veya çevrilmesine de izin verir.

Makro seviyede, algoritma girdideki tekli sayılar üzerinde dolaşır. 0'a bir değer okur, ardından diğer üç sayıya göre uygun konuma yerleştirmek için kabarcık sıralama algoritmasını geçer. Son olarak, şu an dördün en küçüğü olduğu ve hiçbir zaman üçüncü en büyüğü olamayacağı için 0 sayısında bırakılan değeri atar. Döngü sona erdiğinde, 1 sayısı üçüncü en büyüğüdür, bu yüzden diğerlerini atar ve çıkarırız.

En zor kısım (ve ilk enkarnasyonda global loop değişkenlerine sahip olmamın nedeni), onları değiştirip değiştirmemeyi bilmek için iki sayıyı karşılaştırmaktır. İki biti karşılaştırmak için doğruluk tablosunu matematiksel bir ifadeye dönüştürebiliriz; Acc için atılım ! genel değişkenler olmadan bir sayının bitlerini soldan sağa döndürmenin bir yolu olmadığından düşük dereceden yüksek dereceli bitlere kadar bir karşılaştırma algoritması buluyordu. Akümülatörün en düşük dereceli biti, halihazırda incelenmekte olan iki sayının değiştirilip değiştirilmeyeceğini işaret eden bir bayrak saklar.

Bu Acc şüpheleniyorum !! Turing-tamamlandı, ama bunu ispat etme sorununa gitmek istediğimden emin değilim.

İşte yorumlu çözümüm:

# Read and process numbers until the double 0

Count y while N-48 {
    # Read unary number and store it (as binary) in number 0
    # The above loop header consumed the first 1, so we need to add 1 to number 0

    _ + 2

    # Increment number 0 for each 1 in input until next 0

    Count z while N-48 {
        # In this context, the flag indicates a need to carry; set it to 1
        _ - _%2 + 1

        # While carry flag is set, increment the next bit in line
        Count i while _%2 {
            # Set carry flag to 1 if i'th bit is 1, 0 if it's 0
            # Set i'th bit to 1 if it was 0, 0 if it was 1
            _ - _%2 + _/2^(i*4+1)%2 + (-1)^(_/2^(i*4+1)%2)*2^(i*4+1)
        }
    }

    # Bubble number 0 upwards

    Count n while n-3 {
        # The flag (rightmost bit of accumulator) needs to become 1 if we want to swap
        # numbers (n) and (n+1) and 0 if we don't
        # Iterate over bit-groups of accumulator, RTL
        Count i while _/2^(i*4+1) {
            # Adjust the flag as follows:
            # _/2^(i*4+n+1)%4 is the current bit of number (n+1) followed by the current
            # bit of number (n), a value between 0 and 3
            # - If this quantity is 1 (01), number (n) is bigger so far; set flag to 1
            # - If this quantity is 2 (10), number (n+1) is bigger so far; set flag to 0
            # - If this quantity is 0 (00) or 3 (11), the two bits are the same; keep
            #   current value of flag
            _ + (_/2^(i*4+n+1)%4%3 + 1)/2*(_/2^(i*4+n+1)%4%3%2 - _%2)
        }

        # Now swap the two if the flag is 1
        Count i while (_%2)*(_/2^(i*4+1)) {
            # _/2^(i*4+n+1)%2 is the current bit of number (n)
            # _/2^(i*4+n+2)%2 is the current bit of number (n+1)
            _ - (_/2^(i*4+n+1)%2)*2^(i*4+n+1) - (_/2^(i*4+n+2)%2)*2^(i*4+n+2) + (_/2^(i*4+n+2)%2)*2^(i*4+n+1) + (_/2^(i*4+n+1)%2)*2^(i*4+n+2)
        }
    }

    # Discard number 0, setting it to all zeros for the next iteration
    Count i while _/2^(i*4+1) {
        _ - _/2^(i*4+1)%2*2^(i*4+1)
    }
}

# Once the loop is over, all input has been read and the result is in number 1
# Divide by 2 to get rid of flag bit

_ / 2

# Zero out numbers 2 and 3

Count i while _/2^(i*4) {
    _ - _/2^(i*4+2)%2*2^(i*4+2)
}

Count i while _/2^(i*4) {
    _ - _/2^(i*4+3)%2*2^(i*4+3)
}

# Move bits of number 1 down to their final locations

Count i while _/2^i {
    _ - _/2^(i*4+1)%2*2^(i*4+1) + _/2^(i*4+1)%2*2^i
}

# _ now contains the correct answer in decimal; to output in unary:

Count z while z-_ {
    Write 49
}

1 Soruya göre, sadece 1 milyona kadar olan değerlerin desteklenmesi gerekiyor. Kimsenin bundan daha kolay bir çözüm için faydalanmadığı için memnunum - karşılaştırmaları nasıl yapacağınızdan tam olarak emin değilim.


LOL @ the The Bill resmi
bir

7

Picofuck (güvenli)

Picofuck benzer Smallfuck . Sağa bağlanmamış, soldan bağlanmış ikili bir bant üzerinde çalışır. Aşağıdaki komutlara sahiptir:

  • > işaretçiyi sağa hareket ettir

  • <işaretçiyi sola hareket ettirin. İşaretçi banttan düşerse, program sona erer.

  • * işaretçiyi biraz çevir

  • (işaretçideki bit ise 0, diğerine atla)

  • )hiçbir şey yapmayın - Picofuck'ta parantez içinde ifbloklar vardır, whiledöngüler değil .

  • .işaretçiyi bir ascii 0veya bit olarak stdout'a yazın 1.

  • ,Bir 0veya ile karşılaştığımıza kadar stdin'den okuyabilir 1ve imleç üzerindeki bitte saklayabilirsiniz.

Picofuck kodu tamamlandı - programın sonuna gelindiğinde, başlangıçtan itibaren devam ediyor.

Ayrıca, Picofuck iç içe parantezlere izin vermez. Arasında alternatif olmalı bir Picofuck programında görünen parantez (ve ), ile başlayan (ve biten ).

tercüman

Python 2.7 ile yazıldı.

kullanımı: python picofuck.py <source_file>

import sys

def interpret(code):
    # Ensure parentheses match and are not nested.
    in_if_block = False
    for c in code:
        if c == '(':
            if in_if_block:
                print "NESTED IFS DETECTED!!!!!"
                return
            in_if_block = True
        elif c == ')':
            if not in_if_block:
                print "Unmatched parenthesis"
                return
            in_if_block = False
    if in_if_block:
        print "Unmatched parenthesis"
        return


    code_ptr = 0
    array = [0]
    ptr = 0

    while 1:
        command = code[code_ptr]
        if command == '<':
            if ptr == 0:
                break
            ptr -= 1
        elif command == '>':
            ptr += 1
            if ptr == len(array):
                array.append(0)
        elif command == '*':
            array[ptr] = 1-array[ptr]
        elif command == '(':
            if array[ptr] == 0:
                while code[code_ptr] != ')':
                    code_ptr = (code_ptr + 1) % len(code)
        elif command == ',':
            while True:
                c = sys.stdin.read(1)
                if c in ['0','1']:
                    array[ptr] = int(c)
                    break
        elif command == '.':
            sys.stdout.write(str(array[ptr]))
        code_ptr = (code_ptr+1)%len(code)

if __name__ == "__main__":
    with open(sys.argv[1]) as source_file:
        code = source_file.read()
    interpret(code)

Çözüm

Aşağıdaki python 2.7 programı, burada bulunabilecek olan çözümümü ortaya koyuyor

Bu yazıyı daha sonra, bunun nasıl çalıştığı hakkında daha ayrıntılı bir açıklama yaparak düzenleyebilirim, ancak Picofuck'un Turing tamamlandı olduğu ortaya çıktı.

states = {
    "SETUP":(
        "*>",
        "GET_NUMBER",
        "GET_NUMBER"
    ),

    "GET_NUMBER":(
        ",",
        "CHANGE_A",
        "PREPARE_PRINT_C"
    ),

    "GET_DIGIT":(
        ",",
        "CHANGE_A",
        "GOT_DIGIT"
    ),

    "GOT_DIGIT":(
        ">>>>",
        "GO_BACK",
        "GO_BACK"
    ),

    "CHANGE_A":(
        ">",
        "CHANGE_B",
        "SET_A"
    ),

    "SET_A":(
        "*>>>>",
        "GET_DIGIT",
        "GET_DIGIT"
    ),

    "CHANGE_B":(
        ">",
        "CHANGE_C",
        "SET_B"
    ),

    "SET_B":(
        "*>>>",
        "GET_DIGIT",
        "GET_DIGIT"
    ),

    "CHANGE_C":(
        ">",
        "CONTINUE_GET_NUMBER",
        "SET_C"
    ),

    "SET_C":(
        "*>>",
        "GET_DIGIT",
        "GET_DIGIT"
    ),

    "CONTINUE_GET_NUMBER":(
        ">>",
        "GET_DIGIT",
        "GET_DIGIT"
    ),

    "GO_BACK":(
        "<<<<<",
        "FINISH_GO_BACK",
        "GO_BACK"
    ),

    "FINISH_GO_BACK":(
        ">",
        "GET_NUMBER",
        "GET_NUMBER"
    ),

    "PREPARE_PRINT_C":(
        ">>>",
        "PRINT_C",
        "PRINT_C"
    ),

    "PRINT_C":(
        ".>>>>>",
        "PRINT_C",
        "TERMINATE"
    ),

    "TERMINATE":(
        "<",
        "TERMINATE",
        "TERMINATE"
    ),
}

def states_to_nanofuck(states,start_state):
    state_list = list(states)
    state_list.remove(start_state)
    state_list.insert(0,start_state)

    states_by_index = []
    for i,state in enumerate(state_list):
        commands, next1, next0 = states[state]
        states_by_index.append((commands,state_list.index(next1),state_list.index(next0)))


    # setup first state
    fragments = ['*(*>>>>>*<<<<<)>>>>>']

    # reset states that don't match
    for index in range(len(states_by_index)):
        for bool in range(2):
            # at state_0_0
            state_dist = index*3 + bool
            # move state to curstate
            fragments.append('>'*state_dist)
            fragments.append('(*')
            fragments.append(  '<'*state_dist)
            fragments.append(  '<<*>>')
            fragments.append(  '>'*state_dist)
            fragments.append(')')
            fragments.append('<'*state_dist)

            # go to arr
            fragments.append('<<<')

            if bool == 0:
                #flip arr
                fragments.append('*')

            # compute match = arr & curstate
            fragments.append('(>)(>*<)<(<)>')

            if bool == 0:
                #flip arr
                fragments.append('*')

            # reset curstate
            fragments.append('>(*)')

            # move match to matchstate, go back to state_0_0
            matchstate_dist = index*3 + 2
            fragments.append('>(*>')
            fragments.append(  '>'*matchstate_dist)
            fragments.append(  '*')
            fragments.append(  '<'*matchstate_dist)
            fragments.append('<)>')

    #fragments.append('|')

    # do the commands of the matching state
    for index,state in enumerate(states_by_index):
        for bool in range(2):
            # at state_0_0
            matchstate_dist = index*3 + 2
            # move matchstate to curstate
            fragments.append('>'*matchstate_dist)
            fragments.append('(*')
            fragments.append(  '<'*matchstate_dist)
            fragments.append(  '<<*>>')
            fragments.append(  '>'*matchstate_dist)
            fragments.append(')')
            fragments.append('<'*matchstate_dist)

            # if curstate, reset curstate
            fragments.append('<<(*')

            # go to arr
            fragments.append('<')

            # do commands
            commands,next1,next0 = state
            for c in commands:
                if c in '<>':
                    fragments.append(c*(3*len(states_by_index)+5))
                else:
                    fragments.append(c)

            # go to state_0_0
            fragments.append('>>>')

            # set next states
            for dist in [next0*3, next1*3+1]:
                fragments.append('>'*dist)
                fragments.append('*')
                fragments.append('<'*dist)

            # go to curstate
            fragments.append('<<')

            # end if
            fragments.append(')')

            # go to state_0_0
            fragments.append('>>')


    # go back to setup and set it
    fragments.append('<<<<<*')

    code = ''.join(fragments)

    return code



print states_to_nanofuck(states, "SETUP")

2
neredeyse 2 yıl bekler Daha sonra var mı?
Hesap MakinesiFeline

Sadece FYI, sağladığın link artık öldü. '
Conor O'Brien,

Bağlantı indirme gerektiriyor ve ben çok tembelim. Lütfen düzelt.
Hesap MakinesiFeline

@CalculatorFeline Bu 13KB, indirme olarak ele almak çok daha kolaydır.
mbomb007

7

PQRS - Güvenli! / Sağlanan çözüm

temeller

Tüm zımni talimatların dört bellek adresi operası vardır:

P₀ Q₀ R₀ S₀
P₁ Q₁ R₁ S₁
...
Pᵥ₋₁ Qᵥ₋₁ Rᵥ₋₁ Sᵥ₋₁

vDörtlü olarak bellek boyutu nerede .

Pᵢ, Qᵢ, Rᵢ, SᵢMakinenizin doğal boyutunda tamsayılar imzalanmış (örneğin 16, 32 veya 64 bit) biz kelimeler olarak sevk edecektir.

Her dörtlü için i, []dolaylı ifadeyle ima edilen işlem şöyledir:

if (([Pᵢ] ← [Qᵢ] − [Rᵢ]) ≤ 0) go to Sᵢ else go to Pᵢ₊₁

Not Subleq bir alt kümesidir PQSR .

Subleq'in eksiksiz olduğu kanıtlandı, bu yüzden PQRS de tamamlanmalı!

Program Yapısı

PQRS , bir başlangıç ​​başlığını aşağıdaki gibi tanımlar:

H₀ H₁ H₂ H₃ H₄ H₅ H₆ H₇

H₀ H₁ H₂ H₃her zaman ilk talimattır P₀ Q₀ R₀ S₀. H₀için H₃yükleme zamanında tanımlanması gerekir.

PQRS ilkel G / Ç'ye sahiptir ancak bu zorluk için yeterlidir.

H₄ H₅: program başlangıcında, H₅standart girdiden maksimum ASCII karakterini okur ve endekste kelime olarak kaydeder H₄. H₄ve H₅yükleme zamanında tanımlanması gerekir. Okuduktan sonra, okunan H₅karakter sayısına (ve kaydedilen kelimelere) ayarlanacaktır.

H₆ H₇: program sonlandırıldığında, indeksten başlayarak, ASCII karakterleri olarak standart çıktıya sözcükleri H₆içeren tüm baytları yazdırır H₇. H₆ve H₇program sona ermeden önce tanımlanması gerekir. '\0'Çıktıdaki boş baytlar atlanır.

Sonlandırma

Sonlandırma, Sᵢsınırların dışına konulmasıyla i < 0veya i ≥ v.

Hileler

Dörtlülerin Pᵢ Qᵢ Rᵢ Sᵢhizalanması veya art arda olması gerekmez, dörtlü aralıklarla dallara izin verilir.

PQRS Subleq aksine altyordamlarını hayata geçirmek için yeterli esneklik vardır, bu yüzden indirection sahiptir.

Kod kendi kendini değiştirebilir!

tercüman

Tercüman C ile yazılmıştır:

#include <stdlib.h>
#include <stdio.h>

// The "architecture"
enum {P, Q, R, S, START_OF_INPUT, LENGTH_OF_INPUT, START_OF_OUTPUT, LENGTH_OF_OUTPUT};
const int NEXT = S + 1;

// Recommend optimized!
#define OPTIMIZED

#ifdef PER_SPECS
// This may not work on all OSes and architectures - just too much memory needed!
const int K = 1002000200;
#else // OPTIMIZED
// This provides enough space to run the test cases with challenge-optimized.pqrs
const int K = 5200;
#endif

int main(int argc, char *argv[])
{
    int i, *M;
    char *p;
    FILE *program;

    // Allocate enough memory
    M = calloc(K, sizeof(int));

    // Load the program
    for (i = 0, program = fopen(argv[1], "r"); i < K && !feof(program); i++)
        if (!fscanf(program, "%d", M + i))
            break;
    fclose(program);

    // Read in the input
    for (i = 0; i < M[LENGTH_OF_INPUT] && !feof(stdin); i++)
    {
        int c = fgetc(stdin);
        if (c != EOF)
            M[M[START_OF_INPUT] + i] = c;
        else
            break;
    }
    M[LENGTH_OF_INPUT] = i;

    // Execute until terminated
    for (i = 0; i >= 0 && i < K; )
        i = (M[M[P + i]] = M[M[Q + i]] - M[M[R + i]]) <= 0? M[S + i]: i + NEXT;

    // Write the output
    for (i = 0, p = (char *)(M + M[START_OF_OUTPUT]); i < M[LENGTH_OF_OUTPUT] * sizeof(int); i++)
        // Ignore '\0'
        if (p[i])
            fputc(p[i], stdout);

    // Done
    free(M);

    return 0;
}

Kullanmak için yukarıdaki pqrs.c dosyasını kaydedin ve derleyin:

gcc -o pqrs pqrs.c

Örnek program

Echos, 'PQRS-' ile gelen 40 karaktere kadar girdi.

8 8 8 -1 14 40 9 45 0 80 81 82 83 45

Çalıştırmak için yukarıdakileri aşağıdaki gibi kaydedin echo.pqrs:

$ ./prqs echo.pqrs
greetings[enter]
[ctrl-D]
PQRS-greetings

Test vakalarını çalıştırma:

$ ./pqrs challenge-optimized.pqrs < test-1.txt
1

$ ./pqrs challenge-optimized.pqrs < test-2.txt
11111111111111111

$ ./pqrs challenge-optimized.pqrs < test-3.txt
[lots of ones!]

$ ./pqrs challenge-optimized.pqrs < test-3.txt | wc
0       1     773

Tüm test durumları oldukça hızlı çalışıyor, örneğin <500 ms.

Meydan okuma

PQRS istikrarlı sayılabilir, bu nedenle zorluk UTC'de 2015-10-31 13:00 ile başlar ve 2015-11-08 13:00 ile biter.

İyi şanslar!

Çözüm

Dil "Bebek" kullanılan dize oldukça benzer dünyanın ilk kaydedilen program elektronik elektronik makinesi . Bu sayfada, 32 kelime (CRT!) Hafızasından daha az bir tamsayı faktörü bulmak için bir programdır!

Teknik özelliklere uygun bir çözüm yazarken kullandığım işletim sistemi ve kullandığım makine ile uyumlu değildi (biraz eski donanımda Linux Ubuntu türevi). Sadece mevcut olandan daha fazla hafıza talep ediyordu ve çekirdeği boşaltıyordu. Gelişmiş sanal bellek yönetimi olan işletim sistemlerinde veya en az 8 GB belleği olan makinelerde, muhtemelen her özellik için çözümü çalıştırabilirsiniz. Her iki çözümü de sağladım.

Makine dili yazma, hatta belki mikro kodlama gibi, doğrudan PQRS kodlamak çok zordur . Bunun yerine, bir tür meclis dilinde yazmak daha sonra onu “derlemek” daha kolaydır. Aşağıda, test senaryolarını çalıştırmak için optimize edilmiş çözüm için açıklamalı bir montaj dili bulunmaktadır:

; ANNOTATED PQRS ASSEMBLER CODE
; MINIMAL SIZED BUFFERS TO RUN THE TEST CASES

;OFFSET   LABEL       P-OP        Q-OP        R-OP        S-OP
0                     TEMP        ZERO        ZERO        L1

; INPUT AND OUTPUT LOCATIONS AND SIZES
4                     INPUT       4000        
6         L0:         OUTPUT      1000        

; GET CURRENT INPUT
8         L1:         TEMP        INPUT       ASCII_ZERO  L2
12                    SUM         SUM         INC         IGNORE
16                    L1+1        L1+1        INC         IGNORE
20                    TEMP        ZERO        ZERO        L1

; CHECK IF END OF NUMBERS
24        L2:         NUMBERS     SUM         ZERO        L3

; ADVANCE TO NEXT NUMBER
28                    L2          L2          INC         IGNORE

; ADVANCE COUNT
32                    COUNT       COUNT       INC         IGNORE
36                    L1+1        L1+1        INC         IGNORE

; CLEAR SUM AND GO BACK
40                    SUM         ZERO        ZERO        L1

; SORT NUMBERS                
44        L3:         P           NUMBERS     ZERO        LA
48        L4:         Q           NUMBERS+1   ZERO        L9

; COMPARE                
52                    TEMP        Q           P           L8

; SWAP IF OUT OF ORDER
56                    L5+1        L3+1        ZERO        IGNORE
60                    L6          L3+1        ZERO        IGNORE
64                    L6+1        L4+1        ZERO        IGNORE
68                    L7          L4+1        ZERO        IGNORE
72        L5:         TEMP        P           ZERO        IGNORE
76        L6:         P           Q           ZERO        IGNORE
80        L7:         Q           TEMP        ZERO        IGNORE

; INCREMENT INNER INDEX
84        L8:         L4+1        L4+1        INC         IGNORE
88                    TEMP        ZERO        ZERO        L3

; INCREMENT OUTER INDEX AND RESET INNER INDEX
92        L9:         L3+1        L3+1        INC         IGNORE
96                    L4+1        L3+1        INC         IGNORE
100                   TEMP        ZERO        ZERO        L3

; OUTPUT THIRD LARGEST NUMBER
104                   L0+1        NUMBERS+2   ZERO        IGNORE
108       LA:         TEMP        NUMBERS+2   ZERO        EXIT
112       LB:         OUTPUT      ASCII_ONE   ZERO        IGNORE
116                   LB          LB          INC         IGNORE
120                   NUMBERS+2   NUMBERS+2   DEC         EXIT
124                   TEMP        ZERO        ZERO        LA

; SAFETY LOOP – JUST IN CASE IGNORE DOESN'T WORK AS PLANNED!
128       IGNORE:     TEMP        ZERO        ZERO        IGNORE

; CONSTANTS
132       ZERO:        0
133       INC:        -1
134       DEC:         1
135       ASCII_ZERO: 48
136       ASCII_ONE:  49

; VARIABLES
137       TEMP:       [1]
138       SUM:        [1]
139       COUNT:      [1]
140       P:          [1]
141       Q:          [1]

; WORKING SPACE
142       NUMBERS:    [10]

; I/O SPACE
152       INPUT:      [4000]
4152      OUTPUT:     [1000]
5152

Yaptığı girdiyi ayrıştırmak, birliği ikiliye çevirmek, ardından sayıları azalan sırada sayılarla bir kabarcık sıralaması yapmak, sonra nihayetinde ikiliyi birliğe geri dönüştürerek üçüncü en büyük değeri verir.

Not INC(artırma) negatiftir ve DEC(eksiltme) pozitiftir! O kullanıyor Nerede L#ya L#+1kadar P-veya Q-OPtakas, eksiltim, artan vb Çevirici eli için derlendi: s ne oluyor o işaretçileri güncellenmesi olmasıdır PQSR uzaklıklar ile etiketleri ile değiştirilir. PQRS optimize edilmiş çözüm aşağıdadır :

137 132 132 8
152 4000
4152 1000
137 152 135 24
138 138 133 128
9 9 133 128
137 132 132 8
142 138 132 44
24 24 133 128
139 139 133 128
9 9 133 128
138 132 132 8
140 142 132 108
141 143 132 92
137 141 140 84
73 45 132 128
76 45 132 128
77 49 132 128
80 49 132 128
137 140 132 128
140 141 132 128
141 137 132 128
49 49 133 128
137 132 132 44
45 45 133 128
49 45 133 128
137 132 132 44
7 144 132 128
137 144 132 -1
4152 136 132 128
112 112 133 128
144 144 134 -1
137 132 132 108
137 132 132 128
0
-1
1
48
49

Test kodlarını challenge-optimized.pqrsçalıştırmak için yukarıdaki kod kaydedilebilir .

Bütünlüğü için şartname başına kaynak:

; ANNOTATED PQRS ASSEMBLER CODE
; FULL SIZED BUFFERS TO RUN ACCORDING TO SPECS

;OFFSET   LABEL       P-OP        Q-OP        R-OP        S-OP
0                     TEMP        ZERO        ZERO        L1

; INPUT AND OUTPUT LOCATIONS AND SIZES
4                     INPUT       10^9        
6         L0:         OUTPUT      10^6        

; GET CURRENT INPUT
8         L1:         TEMP        INPUT       ASCII_ZERO  L2
12                    SUM         SUM         INC         IGNORE
16                    L1+1        L1+1        INC         IGNORE
20                    TEMP        ZERO        ZERO        L1

; CHECK IF END OF NUMBERS
24        L2:         NUMBERS     SUM         ZERO        L3

; ADVANCE TO NEXT NUMBER
28                    L2          L2          INC         IGNORE

; ADVANCE COUNT
32                    COUNT       COUNT       INC         IGNORE
36                    L1+1        L1+1        INC         IGNORE

; CLEAR SUM AND GO BACK
40                    SUM         ZERO        ZERO        L1

; SORT NUMBERS                
44        L3:         P           NUMBERS     ZERO        LA
48        L4:         Q           NUMBERS+1   ZERO        L9

; COMPARE                
52                    TEMP        Q           P           L8

; SWAP IF OUT OF ORDER
56                    L5+1        L3+1        ZERO        IGNORE
60                    L6          L3+1        ZERO        IGNORE
64                    L6+1        L4+1        ZERO        IGNORE
68                    L7          L4+1        ZERO        IGNORE
72        L5:         TEMP        P           ZERO        IGNORE
76        L6:         P           Q           ZERO        IGNORE
80        L7:         Q           TEMP        ZERO        IGNORE

; INCREMENT INNER INDEX
84        L8:         L4+1        L4+1        INC         IGNORE
88                    TEMP        ZERO        ZERO        L3

; INCREMENT OUTER INDEX AND RESET INNER INDEX
92        L9:         L3+1        L3+1        INC         IGNORE
96                    L4+1        L3+1        INC         IGNORE
100                   TEMP        ZERO        ZERO        L3

; OUTPUT THIRD LARGEST NUMBER
104                   L0+1        NUMBERS+2   ZERO        IGNORE
108       LA:         TEMP        NUMBERS+2   ZERO        EXIT
112       LB:         OUTPUT      ASCII_ONE   ZERO        IGNORE
116                   LB          LB          INC         IGNORE
120                   NUMBERS+2   NUMBERS+2   DEC         EXIT
124                   TEMP        ZERO        ZERO        LA

; SAFETY LOOP – JUST IN CASE IGNORE DOESN'T WORK AS PLANNED!
128       IGNORE:     TEMP        ZERO        ZERO        IGNORE

; CONSTANTS
132       ZERO:        0
133       INC:        -1
134       DEC:         1
135       ASCII_ZERO: 48
136       ASCII_ONE:  49

; VARIABLES
137       TEMP:       [1]
138       SUM:        [1]
139       COUNT:      [1]
140       P:          [1]
141       Q:          [1]

; WORKING SPACE
142       NUMBERS:    [10^6]

; I/O SPACE
1000142   INPUT:      [10^9]
1001000142 OUTPUT:    [10^6]
1002000142

Ve çözüm:

137 132 132 8
1000142 1000000000
1001000142 1000000
137 1000142 135 24
138 138 133 128
9 9 133 128
137 132 132 8
142 138 132 44
24 24 133 128
139 139 133 128
9 9 133 128
138 132 132 8
140 142 132 108
141 143 132 92
137 141 140 84
73 45 132 128
76 45 132 128
77 49 132 128
80 49 132 128
137 140 132 128
140 141 132 128
141 137 132 128
49 49 133 128
137 132 132 44
45 45 133 128
49 45 133 128
137 132 132 44
7 144 132 128
137 144 132 -1
1001000142 136 132 128
112 112 133 128
144 144 134 -1
137 132 132 108
137 132 132 128
0
-1
1
48
49

Yukarıdaki çalıştırmak için, dışarı yorum yapmak gerekecektir #define OPTIMIZEDve ekleme #define PER_SPECSbölgesi pqrs.cve yeniden derleyin.

Bu büyük bir meydan okumaydı - zihinsel antrenmandan gerçekten zevk aldım! Beni eski 6502 montajcı günlerime geri götürdü ...

Eğer PQRS'i “gerçek” bir programlama dili olarak uygulayacak olsaydım, muhtemelen dolaylı erişime ek olarak doğrudan ve iki kat dolaylı erişim için ek modlar ekler, hem de her iki dallı için dolaylı erişim seçenekleriyle göreceli ve mutlak konum eklerdim!


3
Göndermeden önce hazırlanmış bir çözüme sahip olmalısınız.
feersum

1
Evet, çözüm hazır. Anlıyorum ki bazı şüpheler var çünkü dilde çalışmak gerçekten zor. Sinsi bir önizleme görmek isteyenler için, size meydan okumadan önce açıklamamaya söz verdiğiniz sürece, size gönderebilirim!

6

Çinko, Çatlak! @Zgarb tarafından

GitHub'da da mevcuttur .

Dart 1.12 ve Pub'a ihtiyacınız var. pub getAyrıştırma kütüphanesini yalnızca bağımlılığı indirmek için çalıştırın .

İşte bunun umuduyla 30 dakikadan uzun sürüyor! :Ö

Dil

Çinko, operatörlerin yeniden tanımlanması etrafında yönlendirilir. Dilin içindeki tüm operatörleri kolayca yeniden tanımlayabilirsiniz!

Tipik bir Çinko programının yapısı şöyle görünür:

let
<operator overrides>
in <expression>

Yalnızca iki veri türü vardır: tamsayılar ve kümeler. Küme değişmez diye bir şey yoktur ve boş kümelere izin verilmez.

İfade

Aşağıdakiler Çinko'da geçerli ifadelerdir:

Değişmez

Çinko, 1ve benzeri tüm normal tamsayı değişmezlerini destekler -2.

Değişkenler

Çinko değişkenlere sahiptir (çoğu dil gibi). Onlara referans vermek için sadece adı kullanın. Yine çoğu dil gibi!

Ancak, SPyth'lere benzeyen özel bir değişken var Q. İlk kullandığınızda, standart girişten bir satırda okunur ve bir sayı kümesi olarak yorumlanır. Örneğin, giriş satırı 1234231kümeye dönüşür {1, 2, 3, 4, 3, 2, 1}.

ÖNEMLİ NOT!!! Bazı durumlarda, bir operatör geçersiz kılma sonundaki değişmez yanlış bir şekilde ayrıştırılır, bu nedenle onu parantez içine almanız gerekir.

İkili işlemler

Aşağıdaki ikili işlemler desteklenir:

  • Toplama yoluyla +: 1+1.
  • Çıkarma yoluyla -: 1-1.
  • Aracılığıyla Çarpma *: 2*2.
  • Bölüm yoluyla /: 4/2.
  • İle Eşitlik =: 3=3.

Ek olarak, aşağıdaki unary işlemi de desteklenir:

  • Uzunluğu ile #: #x.

Öncelik her zaman doğru bir ilişkidir. Bunu geçersiz kılmak için parantez kullanabilirsiniz.

Kümeler üzerinde sadece eşitlik ve uzunluk çalışmaktadır. Bir tamsayının uzunluğunu almaya çalıştığınızda, dize gösteriminde basamak sayısını alırsınız.

Kavrama ayarlama

Kümeleri değiştirmek için Zinc, küme kavrayışlarına sahiptir. Buna benziyorlar:

{<variable>:<set><clause>}

Bir yan tümce ya da bir yan tümce ya da yan tümcedir.

Bir zaman yan tümcesi benziyor ^<expression>. Şapkayı takip eden ifade bir tamsayı ile sonuçlanmalıdır. When cümlesi kullanıldığında, yalnızca kümedeki expressionsıfır olmayan öğeleri alır . İfade içinde, değişken _kümedeki geçerli dizine ayarlanacaktır. Bu Python'a kabaca eşdeğerdir:

[<variable> for _, <variable> in enumerate(<set>) when <expression> != 0]

Görünüşe göre bir sıralama cümlesi , $<expression>kümeyi değerine göre aşağı doğru sıralar <expression>. Bu Python'a eşittir:

sorted(<set>, key=lambda <variable>: <expression>)[::-1]

İşte bazı anlama örnekleri:

  • Yalnızca s5'e eşit olan küme öğelerini alın :

    {x:s^x=5}
    
  • sÖğeleri kare ise , kümeyi değere göre sıralayın :

    {x:s$x*x}
    

geçersiz kılar

Operatör geçersiz kılma işlemleri, operatörleri yeniden tanımlamanıza izin verir. Buna benziyorlar:

<operator>=<operator>

veya:

<variable><operator><variable>=<expression>

İlk durumda, başka bir operatöre eşit olacak bir operatör tanımlayabilirsiniz. Örneğin, +aslında aracılığıyla çıkarmayı tanımlayabilirim :

+=-

Bunu yaptığınızda, bir işleci sihirli bir işleç olarak yeniden tanımlayabilirsiniz . İki sihirli operatör var:

  • joinbir küme ve bir tam sayı alır ve kümenin içeriğine katılır. Örneğin, birleştirmek tamsayı {1, 2, 3}ile 4sonuçlanacaktır 14243.

  • cutayrıca bir küme ve bir tam sayı alır ve kümeyi tamsayının her oluşumunda bölümlendirir. Kullanılması cutüzerinde {1, 3, 9, 4, 3, 2}ve 3yaratacak {{1}, {9, 4}, {2}}... ANCAK sonuç aslında olacak, böylece herhangi bir tek öğeli setleri, basık vardır {1, {9, 4}, 2}.

İşte +operatörü şu şekilde tanımlayan bir örnek join:

+=join

İkinci durumda, bir işleci verilen ifadeye göre yeniden tanımlayabilirsiniz. Örnek olarak, bu değerleri eklemek için artı işlemini tanımlar ve sonra 1'i ekler:

x+y=1+:x+:y

Ama ne +:? :Dahili sürümü her zaman kullanmak için iki nokta üst üste bir operatöre ekleyebilirsiniz . Bu örnek yerleşiğini kullanır +aracılığıyla +:birbirine numaralarını eklemek için, o zaman bir 1 ekler (hatırlamak, her şey sağ çağrışımlı).

Uzunluk operatörü geçersiz kılmak gibi görünüyor:

#x=<expression>

Neredeyse tüm yerleşik işlemlerin (eşitlik hariç) setin uzunluğunu belirlemek için bu uzunluk operatörünü kullanacağını unutmayın. Bunu tanımladıysanız:

#x=1

Setler üzerinde çalışan Çinko'nun her bölümü =sadece verilen setin ilk elemanı üzerinde çalışır.

Birden fazla geçersiz kılma

Birden çok operatörü virgülle ayırarak geçersiz kılabilirsiniz:

let
+=-,
*=/
in 1+2*3

Baskı

Çinko'da hiçbir şeyi doğrudan yazdıramazsınız. Aşağıdaki ifadenin sonucu inyazdırılacaktır. Bir kümenin değerleri ile ayırıcı birleştirilir. Örneğin, şunu al:

let
...
in expr

Eğer exprkümesidir {1, 3, {2, 4}}, 1324programın, bittikten sonra ekrana basılacaktır.

Hepsini bir araya koy

İşte eklenmiş görünen 2+2ancak sonucun 5 olmasına neden olan basit bir Çinko programı :

let
x+y=1+:x+:y
in 1+2

Çevirmen

Bu giriyor bin/zinc.dart:

import 'package:parsers/parsers.dart';
import 'dart:io';

// An error.
class Error implements Exception {
  String cause;
  Error(this.cause);
  String toString() => 'error in Zinc script: $cause';
}


// AST.
class Node {
  Obj interpret(ZincInterpreter interp) => null;
}

// Identifier.
class Id extends Node {
  final String id;
  Id(this.id);
  String toString() => 'Id($id)';
  Obj interpret(ZincInterpreter interp) => interp.getv(id);
}

// Integer literal.
class IntLiteral extends Node {
  final int value;
  IntLiteral(this.value);
  String toString() => 'IntLiteral($value)';
  Obj interpret(ZincInterpreter interp) => new IntObj(value);
}

// Any kind of operator.
class Anyop extends Node {
  void set(ZincInterpreter interp, OpFuncType func) {}
}

// Operator.
class Op extends Anyop {
  final String op;
  final bool orig;
  Op(this.op, [this.orig = false]);
  String toString() => 'Op($op, $orig)';
  OpFuncType get(ZincInterpreter interp) =>
    this.orig ? interp.op0[op] : interp.op1[op];
  void set(ZincInterpreter interp, OpFuncType func) { interp.op1[op] = func; }
}

// Unary operator (len).
class Lenop extends Anyop {
  final bool orig;
  Lenop([this.orig = false]);
  String toString() => 'Lenop($orig)';
  OpFuncType get(ZincInterpreter interp) =>
    this.orig ? interp.op0['#'] : interp.op1['#'];
  void set(ZincInterpreter interp, OpFuncType func) { interp.op1['#'] = func; }
}

// Magic operator.
class Magicop extends Anyop {
  final String op;
  Magicop(this.op);
  String toString() => 'Magicop($op)';
  Obj interpret_with(ZincInterpreter interp, Obj x, Obj y) {
    if (op == 'cut') {
      if (y is! IntObj) { throw new Error('cannot cut int with non-int'); }
      if (x is IntObj) {
        return new SetObj(x.value.toString().split(y.value.toString()).map(
          int.parse));
      } else {
        assert(x is SetObj);
        List<List<Obj>> res = [[]];
        for (Obj obj in x.vals(interp)) {
          if (obj == y) { res.add([]); }
          else { res.last.add(obj); }
        }
        return new SetObj(new List.from(res.map((l) =>
          l.length == 1 ? l[0] : new SetObj(l))));
      }
    } else if (op == 'join') {
      if (x is! SetObj) { throw new Error('can only join set'); }
      if (y is! IntObj) { throw new Error('can only join set with int'); }
      String res = '';
      for (Obj obj in x.vals(interp)) {
        if (obj is! IntObj) { throw new Error('joining set must contain ints'); }
        res += obj.value.toString();
      }
      return new IntObj(int.parse(res));
    }
  }
}

// Unary operator (len) expression.
class Len extends Node {
  final Lenop op;
  final Node value;
  Len(this.op, this.value);
  String toString() => 'Len($op, $value)';
  Obj interpret(ZincInterpreter interp) =>
    op.get(interp)(interp, value.interpret(interp), null);
}

// Binary operator expression.
class Binop extends Node {
  final Node lhs, rhs;
  final Op op;
  Binop(this.lhs, this.op, this.rhs);
  String toString() => 'Binop($lhs, $op, $rhs)';
  Obj interpret(ZincInterpreter interp) =>
    op.get(interp)(interp, lhs.interpret(interp), rhs.interpret(interp));
}

// Clause.
enum ClauseKind { Where, Sort }
class Clause extends Node {
  final ClauseKind kind;
  final Node expr;
  Clause(this.kind, this.expr);
  String toString() => 'Clause($kind, $expr)';
  Obj interpret_with(ZincInterpreter interp, SetObj set, Id id) {
    List<Obj> res = [];
    List<Obj> values = set.vals(interp);
    switch (kind) {
    case ClauseKind.Where:
      for (int i=0; i<values.length; i++) {
        Obj obj = values[i];
        interp.push_scope();
        interp.setv(id.id, obj);
        interp.setv('_', new IntObj(i));
        Obj x = expr.interpret(interp);
        interp.pop_scope();
        if (x is IntObj) {
          if (x.value != 0) { res.add(obj); }
        } else { throw new Error('where clause condition must be an integer'); }
      }
      break;
    case ClauseKind.Sort:
      res = values;
      res.sort((x, y) {
        interp.push_scope();
        interp.setv(id.id, x);
        Obj x_by = expr.interpret(interp);
        interp.setv(id.id, y);
        Obj y_by = expr.interpret(interp);
        interp.pop_scope();
        if (x_by is IntObj && y_by is IntObj) {
          return x_by.value.compareTo(y_by.value);
        } else { throw new Error('sort clause result must be an integer'); }
      });
      break;
    }
    return new SetObj(new List.from(res.reversed));
  }
}

// Set comprehension.
class SetComp extends Node {
  final Id id;
  final Node set;
  final Clause clause;
  SetComp(this.id, this.set, this.clause);
  String toString() => 'SetComp($id, $set, $clause)';
  Obj interpret(ZincInterpreter interp) {
    Obj setobj = set.interpret(interp);
    if (setobj is SetObj) {
      return clause.interpret_with(interp, setobj, id);
    } else { throw new Error('set comprehension rhs must be set type'); }
  }
}

// Operator rewrite.
class OpRewrite extends Node {
  final Anyop op;
  final Node value;
  final Id lid, rid; // Can be null!
  OpRewrite(this.op, this.value, [this.lid, this.rid]);
  String toString() => 'OpRewrite($lid, $op, $rid, $value)';
  Obj interpret(ZincInterpreter interp) {
    if (lid != null) {
      // Not bare.
      op.set(interp, (interp,x,y) {
        interp.push_scope();
        interp.setv(lid.id, x);
        if (rid == null) { assert(y == null); }
        else { interp.setv(rid.id, y); }
        Obj res = value.interpret(interp);
        interp.pop_scope();
        return res;
      });
    } else {
      // Bare.
      if (value is Magicop) {
        op.set(interp, (interp,x,y) => value.interpret_with(interp, x, y));
      } else {
        op.set(interp, (interp,x,y) => (value as Anyop).get(interp)(x, y));
      }
    }
    return null;
  }
}

class Program extends Node {
  final List<OpRewrite> rws;
  final Node expr;
  Program(this.rws, this.expr);
  String toString() => 'Program($rws, $expr)';
  Obj interpret(ZincInterpreter interp) {
    rws.forEach((n) => n.interpret(interp));
    return expr.interpret(interp);
  }
}


// Runtime objects.
typedef Obj OpFuncType(ZincInterpreter interp, Obj x, Obj y);

class Obj {}

class IntObj extends Obj {
  final int value;
  IntObj(this.value);
  String toString() => 'IntObj($value)';
  bool operator==(Obj rhs) => rhs is IntObj && value == rhs.value;
  String dump() => value.toString();
}

class SetObj extends Obj {
  final List<Obj> values;
  SetObj(this.values) {
    if (values.length == 0) { throw new Error('set cannot be empty'); }
  }
  String toString() => 'SetObj($values)';
  bool operator==(Obj rhs) => rhs is SetObj && values == rhs.values;
  String dump() => values.map((x) => x.dump()).reduce((x,y) => x+y);
  List<Obj> vals(ZincInterpreter interp) {
    Obj lenobj = interp.op1['#'](interp, this, null);
    int len;
    if (lenobj is! IntObj) { throw new Error('# operator must return an int'); }
    len = lenobj.value;
    if (len < 0) { throw new Error('result of # operator must be positive'); }
    return new List<Obj>.from(values.getRange(0, len));
  }
}


// Parser.
class ZincParser extends LanguageParsers {
  ZincParser(): super(reservedNames: ['let', 'in', 'join', 'cut']);
  get start => prog().between(spaces, eof);
  get comma => char(',') < spaces;
  get lp => symbol('(');
  get rp => symbol(')');
  get lb => symbol('{');
  get rb => symbol('}');
  get colon => symbol(':');
  get plus => symbol('+');
  get minus => symbol('-');
  get star => symbol('*');
  get slash => symbol('/');
  get eq => symbol('=');
  get len => symbol('#');
  get in_ => char(':');
  get where => char('^');
  get sort => char('\$');

  prog() => reserved['let'] + oprw().sepBy(comma) + reserved['in'] + expr() ^
            (_1,o,_2,x) => new Program(o,x);
  oprw() => oprw1() | oprw2() | oprw3();
  oprw1() => (basicop() | lenop()) + eq + (magicop() | op()) ^
             (o,_,r) => new OpRewrite(o,r);
  oprw2() => (id() + op() + id()).list + eq + expr() ^
             (l,_,x) => new OpRewrite(l[1], x, l[0], l[2]);
  oprw3() => lenop() + id() + eq + expr() ^ (o,a,_,x) => new OpRewrite(o, x, a);
  magicop() => (reserved['join'] | reserved['cut']) ^ (s) => new Magicop(s);
  basicop() => (plus | minus | star | slash | eq) ^ (op) => new Op(op);
  op() => (basicop() + colon ^ (op,_) => new Op(op.op, true)) | basicop();
  lenop() => (len + colon ^ (_1,_2) => new Lenop(true)) |
             len ^ (_) => new Lenop();
  expr() => setcomp() | unop() | binop() | prim();
  setcomp() => lb + id() + in_ + rec(expr) + clause() + rb ^
               (_1,i,_2,x,c,_3) => new SetComp(i,x,c);
  clausekind() => (where ^ (_) => ClauseKind.Where) |
                  (sort  ^ (_) => ClauseKind.Sort);
  clause() => clausekind() + rec(expr) ^ (k,x) => new Clause(k,x);
  unop() => lenop() + rec(expr) ^ (o,x) => new Len(o,x);
  binop() => prim() + op() + rec(expr) ^ (l,o,r) => new Binop(l,o,r);
  prim() => id() | intlit() | parens(rec(expr));
  id() => identifier ^ (i) => new Id(i);
  intlit() => intLiteral ^ (i) => new IntLiteral(i);
}


// Interpreter.
class ZincInterpreter {
  Map<String, OpFuncType> op0, op1;
  List<Map<String, Obj>> scopes;
  ZincInterpreter() {
    var beInt = (v) {
      if (v is IntObj) { return v.value; }
      else { throw new Error('argument to binary operator must be integer'); }
    };
    op0 = {
      '+': (_,x,y) => new IntObj(beInt(x)+beInt(y)),
      '-': (_,x,y) => new IntObj(beInt(x)-beInt(y)),
      '*': (_,x,y) => new IntObj(beInt(x)*beInt(y)),
      '/': (_,x,y) => new IntObj(beInt(x)/beInt(y)),
      '=': (_,x,y) => new IntObj(x == y ? 1 : 0),
      '#': (i,x,_2) =>
        new IntObj(x is IntObj ? x.value.toString().length : x.values.length)
    };
    op1 = new Map<String, OpFuncType>.from(op0);
    scopes = [{}];
  }

  void push_scope() { scopes.add({}); }
  void pop_scope() { scopes.removeLast(); }
  void setv(String name, Obj value) { scopes[scopes.length-1][name] = value; }
  Obj getv(String name) {
    for (var scope in scopes.reversed) {
      if (scope[name] != null) { return scope[name]; }
    }
    if (name == 'S') {
      var input = stdin.readLineSync() ?? '';
      var list = new List.from(input.codeUnits.map((c) =>
        new IntObj(int.parse(new String.fromCharCodes([c])))));
      setv('S', new SetObj(list));
      return getv('S');
    } else throw new Error('undefined variable $name');
  }
}


void main(List<String> args) {
  if (args.length != 1) {
    print('usage: ${Platform.script.toFilePath()} <file to run>');
    return;
  }
  var file = new File(args[0]);
  if (!file.existsSync()) {
    print('cannot open ${args[0]}');
    return;
  }
  Program root = new ZincParser().start.parse(file.readAsStringSync());
  ZincInterpreter interp = new ZincInterpreter();
  var res = root.interpret(interp);
  print(res.dump());
}

Ve bu içeri giriyor pubspec.yaml:

name: zinc
dependencies:
  parsers: any

Amaçlanan çözüm

let
#x=((x=S)*(-2))+#:x,
/=cut
in {y:{x:S/0$#:x}^_=2}

1
Kümelerin sıralandığını ve kopyalanabileceğini, bu yüzden temelde listeler olduklarını doğru anlıyor muyum? Ayrıca, eğer joinkarışık bir set yaparsam {1,{3,2}}, bir hata olur mu? Dart'ı şu anda yükleyemiyorum, bu yüzden kendimi kontrol edemiyorum.
Zgarb

@Zgarb Evet, kümeler bu durumda temel olarak listelenir. Karma setlere katılmak bir hata olmalı , ancak tercüman aslında ATM'yi çöker ...
kirbyfan64sos

Tercümanı nasıl çalıştırırım? Eğer sadece dart bin/zinc.dart test.znc'file:///D:/Development/languages/zinc/bin/zinc.dart': error: line 323 pos 41: unexpected token '?'var input = stdin.readLineSync() ?? '';
Martin Ender


1
@ Zgarb Spesifikasyonda, eşitlik dışındaki tüm yerleşik işlemlerin uzunluk operatörünü ne zaman kullandığını söylediğimi hatırlayın. Bunun dönmek overrode -2+#:Sverildiğinde Siki arka sıfırları kesilmiş olan. Nasıl çözüleceğini umuyordum. Ve ^seti tersine
çevirmemeliyiz

5

Pusula Çorbası ( cardboard_box çatlatan )

Tercüman: C ++

Pusula Çorbası, sonsuz 2 boyutlu bant içeren bir Turing makinesi gibidir. Ana yakalama, talimat hafızası ve veri hafızasının aynı alanda olması ve programın çıktısının, bu boşluğun tüm içeriği olmasıdır.

görüntü tanımını buraya girin

Nasıl çalışır

Bir program 2 boyutlu bir metin bloğudur. Program alanı ilk karakterle (0,0) gösterilen tüm kaynak koduyla başlar. Program alanının geri kalan kısmı sonsuzdur ve boş karakterlerle (ASCII 0) başlatılır.

Program alanı etrafında hareket edebilen iki işaretçi vardır:

  • Yürütme işaretçisinin bir konumu ve yönü vardır (Kuzey, Güney, Doğu veya Batı). Her tıklatma, yürütme işaretçisinin altındaki komut yürütülür, ardından yürütme işaretçisinin geçerli yönünde hareket eder. Yürütme işaretçisi !karakterin bulunduğu yerde veya yoksa (0,0) konumunda doğuya (pozitif x) hareket etmeye başlar .
  • Veri işaretçisi sadece bir yere sahiptir. Bu talimatlara taşınır x, X, y, ve Y. @Karakterin bulunduğu yerde veya yoksa (0,0) ile başlar .

Giriş

Stdin içeriği, >karakterin bulunduğu yerden başlayarak program alanına veya yoksa (0,0) olarak basılır .

Çıktı

Yürütme işaretçisini geri dönüşü olmayan sınırların dışında çalıştırıldığında, program sona erer. Çıktı, o sırada program alanının içeriğinin tamamıdır. Stdout ve 'result.txt' ye gönderilir.

Talimatlar

  • n - yürütme işaretçisini North'a yönlendirir (negatif y)
  • e - yürütme işaretçisini Doğu'ya yönlendirir (pozitif x)
  • s - yürütme işaretçisini Güney'e yönlendirir (pozitif y)
  • w - yürütme işaretçisini West'e yönlendirir (negatif x)
  • y - veri işaretçisini Kuzey (negatif y) olarak hareket ettirir
  • X - veri işaretçisini Doğu'ya (pozitif x) taşır
  • Y - veri işaretçisini Güney'e taşır (pozitif y)
  • x - veri işaretçisini West (negatif x) olarak hareket ettirir
  • p- yürütme işaretçisinin veri işaretçisinde karşılaştığı bir sonraki karakteri yazar. Bu karakter bir talimat olarak yürütülmez.
  • j- yürütme işaretçisinin karşılaştığı bir sonraki karakteri veri işaretçisinin altındaki karaktere karşı denetler. Bu karakter bir talimat olarak yürütülmez. Aynılarsa, yürütme işaretçisi bir sonraki karakterin üzerine atlar.
  • c - boş karakteri veri göstergesine yazar.
  • * - kesme noktası - sadece tercümanın kırılmasına neden olur.

Diğer tüm karakterler yürütme işaretçisiyle yoksayılır.

tercüman

Tercüman kaynak dosyayı argüman olarak alır ve stdin'deki girdiyi alır. Kodda ( *) bir breakpoint komutuyla çağırabileceğiniz adım adım hata ayıklayıcıya sahiptir . Kırıldığında, yürütme işaretçisi ASCII 178 (daha koyu gölgeli blok) ve veri işaretçisi ASCII 177 (daha açık gölgeli blok) olarak gösterilir.

#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include <stdio.h>

// Compass Soup programming language interpreter
// created by Brian MacIntosh (BMacZero)
// for https://codegolf.stackexchange.com/questions/61804/create-a-programming-language-that-only-appears-to-be-unusable
//
// 31 October 2015

struct Point
{
    int x, y;
    Point(int ix, int iy) { x = ix; y = iy; };
    bool operator==(const Point &other) const
    {
        return other.x == x && other.y == y;
    }
    bool operator!=(const Point &other) const
    {
        return other.x != x || other.y != y;
    }
};

struct Bounds
{
    int xMin, xMax, yMin, yMax;
    Bounds(int xmin, int ymin, int xmax, int ymax)
    {
        xMin = xmin; yMin = ymin; xMax = xmax; yMax = ymax;
    }
    bool contains(Point pt)
    {
        return pt.x >= xMin && pt.x <= xMax && pt.y >= yMin && pt.y <= yMax;
    }
    int getWidth() { return xMax - xMin + 1; }
    int getHeight() { return yMax - yMin + 1; }
    bool operator==(const Bounds &other) const
    {
        return other.xMin == xMin && other.xMax == xMax && other.yMin == yMin && other.yMax == yMax;
    }
    bool operator!=(const Bounds &other) const
    {
        return other.xMin != xMin || other.xMax != xMax || other.yMin != yMin || other.yMax != yMax;
    }
};

int max(int a, int b) { return a > b ? a : b; }
int min(int a, int b) { return a < b ? a : b; }

Bounds hull(Point a, Bounds b)
{
    return Bounds(min(a.x, b.xMin), min(a.y, b.yMin), max(a.x, b.xMax), max(a.y, b.yMax));
}

Bounds hull(Bounds a, Bounds b)
{
    return Bounds(min(a.xMin, b.xMin), min(a.yMin, b.yMin), max(a.xMax, b.xMax), max(a.yMax, b.yMax));
}

Bounds programBounds(0,0,0,0);
char** programSpace;

Point execPtr(0,0);
Point execPtrDir(1,0);
Point dataPtr(0,0);
Point stdInPos(0,0);

bool breakpointHit = false;
char breakOn = 0;

/// reads the character from the specified position
char read(Point pt)
{
    if (programBounds.contains(pt))
        return programSpace[pt.x - programBounds.xMin][pt.y - programBounds.yMin];
    else
        return 0;
}

/// read the character at the data pointer
char readData()
{
    return read(dataPtr);
}

/// read the character at the execution pointer
char readProgram()
{
    return read(execPtr);
}

/// gets the bounds of the actual content of the program space
Bounds getTightBounds(bool debug)
{
    Bounds tight(0,0,0,0);
    for (int x = programBounds.xMin; x <= programBounds.xMax; x++)
    {
        for (int y = programBounds.yMin; y <= programBounds.yMax; y++)
        {
            if (read(Point(x, y)) != 0)
            {
                tight = hull(Point(x, y), tight);
            }
        }
    }
    if (debug)
    {
        tight = hull(dataPtr, tight);
        tight = hull(execPtr, tight);
    }
    return tight;
}

/// ensure that the program space encompasses the specified rectangle
void fitProgramSpace(Bounds bounds)
{
    Bounds newBounds = hull(bounds, programBounds);

    if (newBounds == programBounds) return;

    // allocate new space
    char** newSpace = new char*[newBounds.getWidth()];

    // copy content
    for (int x = 0; x < newBounds.getWidth(); x++)
    {
        newSpace[x] = new char[newBounds.getHeight()];
        for (int y = 0; y < newBounds.getHeight(); y++)
        {
            Point newWorldPos(x + newBounds.xMin, y + newBounds.yMin);
            newSpace[x][y] = read(newWorldPos);
        }
    }

    // destroy old space
    for (int x = 0; x < programBounds.getWidth(); x++)
    {
        delete[] programSpace[x];
    }
    delete[] programSpace;

    programSpace = newSpace;
    programBounds = newBounds;
}

/// outputs the current program space to a file
void outputToStream(std::ostream &stream, bool debug)
{
    Bounds tight = getTightBounds(debug);
    for (int y = tight.yMin; y <= tight.yMax; y++)
    {
        for (int x = tight.xMin; x <= tight.xMax; x++)
        {
            char at = read(Point(x, y));
            if (debug && x == execPtr.x && y == execPtr.y)
                stream << (char)178;
            else if (debug && x == dataPtr.x && y == dataPtr.y)
                stream << (char)177;
            else if (at == 0)
                stream << ' ';
            else
                stream << at;
        }
        stream << std::endl;
    }
}

/// writes a character at the specified position
void write(Point pt, char ch)
{
    fitProgramSpace(hull(pt, programBounds));
    programSpace[pt.x - programBounds.xMin][pt.y - programBounds.yMin] = ch;
}

/// writes a character at the data pointer
void write(char ch)
{
    write(dataPtr, ch);
}

/// writes a line of text horizontally, starting at the specified position
void writeLine(Point loc, std::string str, bool isSource)
{
    fitProgramSpace(Bounds(loc.x, loc.y, loc.x + str.size(), loc.y));
    for (unsigned int x = 0; x < str.size(); x++)
    {
        programSpace[x + loc.x][loc.y] = str[x];

        // record locations of things
        if (isSource)
        {
            switch (str[x])
            {
            case '>':
                stdInPos = Point(loc.x + x, loc.y);
                break;
            case '!':
                execPtr = Point(loc.x + x, loc.y);
                break;
            case '@':
                dataPtr = Point(loc.x + x, loc.y);
                break;
            }
        }
    }
}

void advanceExecPtr()
{
    execPtr.x += execPtrDir.x;
    execPtr.y += execPtrDir.y;
}

void breakpoint()
{
    breakpointHit = true;
    outputToStream(std::cout, true);
    std::cout << "[Return]: step | [Space+Return]: continue | [<char>+Return]: continue to <char>" << std::endl;
    while (true)
    {
        std::string input;
        std::getline(std::cin, input);
        if (input.size() == 0)
        {
            break;
        }
        else if (input.size() == 1)
        {
            if (input[0] == ' ')
            {
                breakpointHit = false;
                break;
            }
            else
            {
                breakOn = input[0];
                breakpointHit = false;
                break;
            }
        }
    }
}

int main(int argc, char** argv)
{
    if (argc != 2)
    {
        printf("Usage: CompassSoup <source-file>");
        return 1;
    }

    // open source file
    std::ifstream sourceIn(argv[1]);

    if (!sourceIn.is_open())
    {
        printf("Error reading source file.");
        return 1;
    }

    programSpace = new char*[1];
    programSpace[0] = new char[1];
    programSpace[0][0] = 0;

    // read starting configuration
    std::string line;
    int currentLine = 0;
    while (std::getline(sourceIn, line))
    {
        writeLine(Point(0, currentLine), line, true);
        currentLine++;
    }

    sourceIn.close();

    // take stdin
    std::string input;
    std::cout << ">";
    std::cin >> input;
    std::cin.ignore();
    writeLine(stdInPos, input, false);

    // execute
    while (programBounds.contains(execPtr))
    {
        if (execPtrDir.x == 0 && execPtrDir.y == 0)
        {
            printf("Implementation error: execPtr is stuck.");
            break;
        }

        advanceExecPtr();

        char command = readProgram();

        // breakpoint control code
        if (breakpointHit || (breakOn != 0 && command == breakOn))
        {
            breakOn = 0;
            breakpoint();
        }

        switch (command)
        {
        case 'n':
            execPtrDir = Point(0,-1);
            break;
        case 'e':
            execPtrDir = Point(1,0);
            break;
        case 's':
            execPtrDir = Point(0,1);
            break;
        case 'w':
            execPtrDir = Point(-1,0);
            break;
        case 'x':
            dataPtr.x--;
            break;
        case 'X':
            dataPtr.x++;
            break;
        case 'y':
            dataPtr.y--;
            break;
        case 'Y':
            dataPtr.y++;
            break;
        case 'p':
            advanceExecPtr();
            write(readProgram());
            break;
        case 'j':
            advanceExecPtr();
            if (readData() == readProgram())
            {
                advanceExecPtr();
            }
            break;
        case 'c':
            write(0);
            break;
        case '*':
            breakpoint();
            break;
        }
    }

    std::ofstream outputFile("result.txt");
    outputToStream(outputFile, false);
    outputToStream(std::cout, false);
    outputFile.close();
}

Örnekler

Selam Dünya

Hello, World!

Kedi

>

Eşlik: sıfır ('0') ile sonlandırılmış bir karakter dizisini kabul eder. Girişteki yes1 sayısı tek ise çıktının ilk satırındaki çıktılar, aksi takdirde çıktı verilir |.

|>
!--eXj1s-c-eXj0s-c-exj|s-pyXpeXps
   c   |   c   |   |   |
  cn0j-w---n1j-w   n---w

İpuçları

İyi bir metin düzenleyici kullanmalı ve 'Insert' tuşunun işlevselliğini makul şekilde kullanmalı ve aynı anda birden fazla satıra metin eklemek veya silmek için 'Alt-Drag' kullanmalısınız.

Çözüm

İşte benim çözümüm. Karton_box'ınki kadar hoş değil çünkü kaynak kodun kendisini silmesi gerekiyordu. Ayrıca, tüm kodu silmek ve yalnızca yanıtı bırakmak için bir yol bulabileceğimi umuyordum, ancak yapamadım.

Benim yaklaşımım, farklı 1s dizilerini farklı çizgilere bölmek , ardından 1diğerlerini vuruncaya kadar hepsinin "düşmesini" sağlayarak sıralamak 1ve girişten sonraki üçüncü çizgi hariç her şeyi silmek oldu.

  • Sağ alt köşesindeki büyük blok s'yi #A#okur 1ve bunları okunana kadar bölmenin son satırına kopyalar 0.
  • #B#bir saniye denetler 0ve kuzeye gider #D#bir tane var. Aksi takdirde, sonuncusunu #C#koyarak yeni bir bölme çizgisi başlatır |ve geri gider #A#.
  • Yukarıdaki ve üstündeki blok #F#, yerçekimi kodudur. 1İlk satırın sonuna kadar yürür ve 1ya da isabet edinceye kadar yukarı taşır -. Bunu yapamazsa, satırın +önüne koyarak bitmiş olarak işaretler .
  • #G#tüm gereksiz bölünmeleri #H#siler ve parantez arasındaki tüm kodu ve stdin'i siler.

Kod:

 s-----------------------w
 s-c-w  s-c-w  s---w    e+-
 eXj)nc-eXj)nc-exj(ncyj(nn
(n-----------------------------------------w                      ))
(  #H#                             s---w   |                      ))
(                                  exj+ncyxn                      ))
(                                  |                              ))
(                      s---w   s-c-+w                             ))
(                      exj+ncy-eXj1nn                             ))
(                      |                                          ))
(         s---w    s-c-+w    s+pxw                                ))
(         eyj-n-YY-eXj1nn    |  sn1jX--w           e----s         ))
(         |                  Y  x     e+---s e---s ns1jyw         ))
(      ej+n------s           j  |     nn+jYw-n+jxw-Yw   |         ))
(      Y   ec----s      e---s|  |                       1         ))
(      c   ns1jX-wYcYYY-n-jyww  |                       p         ))
(      ns+jxw      #G#       e--s                       Y         ))
(       e---n                   |               s------w|         ))
(                               |               |   ej-nn         ))
(             s--w              e----s   exc----eyj1n---n         ))
(#A#          p e+---s   s---w       |#F#|                        ))
(e----se---s  1 ||   |   exj|n----p+YeXj1ns                       ))
(ns-jXwn-jyw--w-nn1jXw   c #D#       n----w                       ))
( |        |         |   |                                        ))
( |        n---------+---+-------------|pw            s---w s---w ))
( |                  |   |     exp)XYs   |            eyj-nYeXj0ns)
( |         s---ws---+w  n-----+-----+---+------------+----------w))
( |         |   ||   ||  e--yp)n     e---+--s         |           )
( |     e-c-exj|neYj|nn  |     #C#       |  |         p           ))
( |     |                |     s---w s---+w s---w s---+w          ))
( |     |          #B#  e+s    |   | |   || |   | |   ||          ))
(!ep-Yj0n-c----------Xj0nne----exj|n-eYj|nn exj|n-eYj|nn          ))
(-@
 |>


Kahretsin, çok yakın! Bu gece eve geldiğimde çözümümü paylaşacağım.
BMac

Eşlik programının çalışmasını sağlayamıyorum. Başlangıçta bir hata ayıklama talimatı olması gerekiyor mu? Eğer adım atarsam sonsuz bir döngüde sıkışıp kalırsam, Yanlış yaptığım bir fikrin var mı?
feersum

Başlangıçta orada colmaması gereken bir ekstra vardı gibi görünüyor . Onardım. Ayrıca sorunuma çözümümü de ekledim.
BMac

4

Acc! , Ppperry tarafından Cracc'd

Bu dil bir döngü yapısına, temel tamsayı matematiğine, karakter I / O ve bir akümülatöre (yani adı) sahiptir. Sadece bir akümülatör. Böylece, isim.

tablolar

Komutlar satır satır ayrıştırılır. Üç tür komut vardır:

  1. Count <var> while <cond>

Sayımlar <var>kadar 0 sürece gelen <cond>, sıfırdan farklı C-tarzı eşdeğerdir for(<var>=0; <cond>; <var>++). Döngü sayacı herhangi bir tek küçük harf olabilir. Koşul, mutlaka döngü değişkenini içermeyen, herhangi bir ifade olabilir. Döngü, koşulun değeri 0 olduğunda durur.

Döngüler K & R tarzı kaşlı ayraçlar gerektirir (özellikle, Stroustrup varyantı ):

Count i while i-5 {
 ...
}
  1. Write <charcode>

Verilen ASCII / Unicode değerine sahip tek bir karakteri stdout'a verir. Karakter kodu herhangi bir ifade olabilir.

  1. ifade

Tek başına duran herhangi bir ifade değerlendirilir ve akümülatöre (olarak erişilebilir _) geri atanır . Dolayısıyla, örneğin, 3akümülatörü 3'e ayarlayan bir ifadedir; _ + 1akümülatörü arttırır; ve _ * Nbir karakter okur ve akümülatörü karakter koduyla çarpar.

Not: akümülatör doğrudan atanabilecek tek değişkendir; Döngü değişkenleri ve Nhesaplamalarda kullanılabilir ancak değiştirilmez.

Akümülatör başlangıçta 0'dır.

İfade

Bir ifade, tamsayı değişmezleri, toplayıcı için loop değişkenleri ( a-z) _ve Nbir karakteri okuyup her kullanıldığında karakter kodunu değerlendiren özel değeri içerebilir. Not: bu, her karakteri okumak için yalnızca bir kez çekim yapabileceğiniz anlamına gelir; bir dahaki Nsefere bir dahaki sefere okuyacaksın.

Operatörler:

  • +, ilave
  • -, çıkarma; tekli olumsuzlama
  • *, çarpma işlemi
  • /, tamsayı bölümü
  • %, modulo
  • ^üstel

Parantez, işlemlerin önceliğini zorlamak için kullanılabilir. Bir ifadedeki herhangi bir karakter, bir sözdizimi hatasıdır.

Boşluk ve yorumlar

Lider ve takip eden boşluk ve boş satırlar dikkate alınmaz. Döngü başlıklarındaki boşluk, tam olarak gösterildiği gibi olmalıdır, ayrıca döngü başlığı ve açılış küme parantezi arasında tek bir boşluk bırakılmalıdır. İfadelerin içindeki boşluklar isteğe bağlıdır.

# tek satırlı bir yorum başlatır.

Giriş çıkış

Acc! giriş olarak tek bir karakter satırı bekler. Her giriş karakteri sırayla alınabilir ve karakter kodu kullanılarak işlenir N. Satırın son karakterini okumaya çalışmak bir hataya neden olur. Bir karakter, karakter kodunu ifadeye geçirerek çıkarılabilir Write.

tercüman

Tercüman (Python 3 ile yazılmış) Acc! Python içine kodlayın ve execs.

import re, sys

def main():
    if len(sys.argv) != 2:
        print("Please supply a filename on the command line.", file=sys.stderr)
        return
    codeFile = sys.argv[1]
    with open(codeFile) as f:
        code = f.readlines()
    code = translate(code)
    exec(code, {"inputStream": (ord(char) for char in input())})

def translate(accCode):
    indent = 0
    loopVars = []
    pyCode = ["_ = 0"]
    for lineNum, line in enumerate(accCode):
        if "#" in line:
            # Strip comments
            line = line[:line.index("#")]
        line = line.strip()
        if not line:
            continue
        lineNum += 1
        if line == "}":
            if indent:
                loopVar = loopVars.pop()
                if loopVar is not None:
                    pyCode.append(" "*indent + loopVar + " += 1")
                indent -= 1
            else:
                raise SyntaxError("Line %d: unmatched }" % lineNum)
        else:
            m = re.fullmatch(r"Count ([a-z]) while (.+) \{", line)
            if m:
                expression = validateExpression(m.group(2))
                if expression:
                    loopVar = m.group(1)
                    pyCode.append(" "*indent + loopVar + " = 0")
                    pyCode.append(" "*indent + "while " + expression + ":")
                    indent += 1
                    loopVars.append(loopVar)
                else:
                    raise SyntaxError("Line %d: invalid expression " % lineNum
                                      + m.group(2))
            else:
                m = re.fullmatch(r"Write (.+)", line)
                if m:
                    expression = validateExpression(m.group(1))
                    if expression:
                        pyCode.append(" "*indent
                                      + "print(chr(%s), end='')" % expression)
                    else:
                        raise SyntaxError("Line %d: invalid expression "
                                          % lineNum
                                          + m.group(1))
                else:
                    expression = validateExpression(line)
                    if expression:
                        pyCode.append(" "*indent + "_ = " + expression)
                    else:
                        raise SyntaxError("Line %d: invalid statement "
                                          % lineNum
                                          + line)
    return "\n".join(pyCode)

def validateExpression(expr):
    "Translates expr to Python expression or returns None if invalid."
    expr = expr.strip()
    if re.search(r"[^ 0-9a-z_N()*/%^+-]", expr):
        # Expression contains invalid characters
        return None
    elif re.search(r"[a-zN_]\w+", expr):
        # Expression contains multiple letters or underscores in a row
        return None
    else:
        # Not going to check validity of all identifiers or nesting of parens--
        # let the Python code throw an error if problems arise there
        # Replace short operators with their Python versions
        expr = expr.replace("^", "**")
        expr = expr.replace("/", "//")
        # Replace N with a call to get the next input character
        expr = expr.replace("N", "inputStream.send(None)")
        return expr

if __name__ == "__main__":
    main()


3

GoToTape (Güvenli)

(Eskiden Simp-plex olarak bilinir.)

Bu dil basit. Ana akış kontrolü, en doğal ve kullanışlı kontrol şekli olan goto'dur.

Dil özellikleri

Veriler bir kasette ve bir akümülatörde depolanır. Tamamen imzasız entegrasyonlarla çalışır. Her karakter komuttur. Aşağıdaki komutların tümü:

  • Harfler: a- sırasıyla - 'a yapılan zifadelerdir .AZ
  • :: akümülatörü ASCII değerine, girişten char değerine ayarlayın.
  • ~: akümülatördeki ASCII değerinin değerini gösterir.
  • &: 1 veya daha fazla ise akümülatörden bir tane çıkartın, aksi halde bir tane ekleyin.
  • |: aküye bir tane ekleyin.
  • <: veri işaretçisini 0'a ayarlayın.
  • +: veri göstergesindeki veri hücresini artırmak; işaretçiyi +1 hareket ettirin.
  • -: eğer pozitifse, veri göstergesindeki veri hücresinden bir tane çıkartın; işaretçiyi +1 hareket ettirin.
  • [...]: kodunu n kere çalıştırın, burada n veri göstergesindeki banttaki sayıdır (iç içe geçemez).
  • /: akümülatör 0 ise bir sonraki talimatı atlayın.

Yorumlayıcı (C ++)

#include <iostream>
#include <memory.h>
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

int serch(char* str,char ch){
    for(int i = 0;str[i];i++){
        if(str[i]==ch)
            return i;
    }
    return -1;
}

void runCode(char* code){
    int i = 0;
    char c;
    unsigned int* tape;
    tape = new unsigned int[1000003];
    memset(tape,0,1000003*sizeof(int));
    unsigned int p=0;
    unsigned int a=0;
    unsigned int n;
    unsigned int s;

    while(c=code[i]){
        if('A'<=c && c<='Z');
        if('a'<=c && c<='z')i=serch(code, c+'A'-'a');
        if(':'==c)a=cin.get();
        if('+'==c)tape[p++]++;
        if('-'==c)tape[p++] += tape[p]?-1:0;
        if('|'==c)a++;
        if('&'==c)a=a?a-1:1;
        if('<'==c)p=0;
        if('['==c){if(tape[p]){n=tape[p];s=i;}else i+=serch(code+i,']');};
        if(']'==c)i=--n?i:s;
        if('~'==c)cout<<(char)a;
        if('/'==c)i+=a?0:1;
        if('$'==c)p=a;
        i++;
    }
    delete[](tape);
}

int main(int argc, char* argv[]) {
    if(argc == 2){

        ifstream sorceFile (argv[1]);
        string code(static_cast<stringstream const&>(stringstream() << sorceFile.rdbuf()).str());
        runCode((char*)code.c_str());
    }else
        cout << "Code file must be included as a command-line argument \n";
    return 0;
}

İyi eğlenceler!

Çözüm

A:+&&&&&&&&&&/gbG&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&/a<aB<[|]C[&]-[|]/c<[|]D[&]-[|]/d<[|]+E[&]|||||||||||||||||||||||||||||||||||||||||||||||||~X&/x-[|]/e


2
C ++ kodun beni öldürüyor! callocBunun yerine kullandığınız bir neden var mı new char, C stilini yazarken, C stilini hafıza yönetimini kullanıp, kodu değiştirdiğimizde her seferinde C ++ dosyasını yeniden derleyelim ve a yerine 20 ifs kullandık switchmı? Şikayet etmiyorum, ama gözlerim şu anda kanıyor ...: O
kirbyfan64sos

3
Benek tercümanı ete sabitledim.
MegaTom

@ kirbyfan64sos Kod bozuk. Bunu çabucak bir araya getirdim ve yapmam gerekeni yapmamış olabilirim. Ana işlev, kodu giriş olarak almak için değiştirilebilir. Aslında bunu şimdi yapacağımı düşünüyorum ...
MegaTom

1
Soru, tercümanların programın komut satırında bir dosya adı alması gerektiğini söylüyor .
Dennis,

İşte bir dosyayı bir dizgede okumanın kısa yolları . Sonra str.c_str()almak için arayın char*.
feersum

0

Neredeyse tüm ezoterik dillerin okunamadığı görüldüğü için bu kötü bir fikirdi.
Ama işte gidiyor:

Pylongolf2 beta6

Yığına itmek

Yığına itmek, diğer dillerde olduğu gibi farklı davranır.
Kod 78iter 7ve 8yığına girer, ancak Pylongolf'ta iter 78.
Pylongolf2'de bu durum değiştirilebilir Ü.

Komutları

) Print the stack.
Ü Toggle the method Pylongolf2 uses for pushing to stack.
a The useless command, removes and adds the selected item in the same place.
c Ask for input.
n Convert string to a number.
" Toggle string mode for pushing text to the stack.
s Convert a number to a string. ╨ Encode the selected item (it must be a string).
_ Duplicate the selected item next to itself.
b Swap places between the selected item and the one before.
d Set the selected item to the last one.
m Move the selected item to the end of the stack.
@ Select an item. (Number required after this command as an argument).
w Wait a specified amount of time (the time is taken from the stack).
= Compare the selected item to the one before. (WARNING. THIS DELETES THE 2 ITEMS AND PLACES A true OR A false) (V2 beta)
~ Print the stack nicely. (V2 beta)
² Square a number. (V3 beta)
| Split a string to an array by the character after |. (V4 beta)
♀ Pop the array. (the contents are left in the stack) (V4 beta)
> Begin a while statement. (V5 beta)
< Loop back to the beginning of the while statement. (V5 beta)
! Break out of the while statements. (V5 beta)
? An if statement, does nothing if the selected item is a `true` boolean. (V6 beta)
¿ If an if statement is `false`, the interpreter skips everything to this character. (V6 beta)

Dize Birleştirme ve Regex Örüntüsünü Dizeden Kaldırma

+ Sembolü dizeleri birleştirir.
Bir dizgeden bir regex desenini izleyen karakterleri kaldırmak için - sembolünü kullanabilirsiniz:

c╨2"[^a-zA-Z]"-~

Bu kod girdi alır ve eşleşen tüm desenleri kaldırarak tüm alfabetik olmayan karakterleri kaldırır [^a-zA-Z].
Seçilen öğenin regex olması ve önceki öğenin düzenlenecek dize olması gerekir.

Eğer İfadeler

İf ifadeleri yapmak =için, seçilen öğeyi ve sonraki öğeyi karşılaştırmak için
Bu yer a trueya da a yerlerine falseyerleştirilir.
Komut ?bu booleanı kontrol ediyor.
Eğer öyleyse truehiçbir şey yapmaz ve tercüman devam eder.
Eğer falseöyleyse, tercüman en yakın ¿karaktere geçer.

Github sayfasından alınmıştır.

Pylongolf2 tercümanı (Java):

package org.midnightas.pylongolf2;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.Scanner;

public class Pylongolf {

    public static final void main(String[] args) throws Exception {
        String content = new String(Files.readAllBytes(Paths.get(new File(args[0]).toURI()))) + " ";
        boolean fullreadMode = true;
        List<Object> stack = new ArrayList<Object>();
        List<Integer> whileStatements = new ArrayList<Integer>();
        HashMap<String, Object> vars = new HashMap<String, Object>();
        int ifStatements = 0;
        Scanner scanner = new Scanner(new UnclosableDecorator(System.in));
        int selectedIndex = 0;
        for (int cl = 0; cl < content.length(); cl++) {
            char c = content.charAt(cl);
            if (isNumber(c)) {
                if (!fullreadMode) {
                    stack.add(Double.parseDouble(c + ""));
                } else {
                    String number = "";
                    for (int cl0 = cl; cl0 < content.length(); cl0++) {
                        if (isNumber(content.charAt(cl0))) {
                            number += content.charAt(cl0);
                        } else {
                            cl = cl0 - 1;
                            stack.add(Double.parseDouble(number));
                            break;
                        }
                    }
                }
            } else if (c == ')') {
                System.out.println(Arrays.toString(stack.toArray()));
            } else if (c == 'Ü') {
                fullreadMode = !fullreadMode;
            } else if (c == '+') {
                if (stack.get(selectedIndex) instanceof Object[]) {
                    Object[] obj = (Object[]) stack.remove(selectedIndex);
                    Double dbl = new Double(0d);
                    for (Object o : obj) {
                        dbl += (Double) o;
                    }
                    stack.add(selectedIndex, dbl);
                } else {
                    Object obj0 = stack.remove(selectedIndex);
                    Object obj1 = stack.remove(selectedIndex);
                    if (obj0 instanceof Number && obj1 instanceof Number)
                        stack.add(((Number) obj0).doubleValue() + ((Number) obj1).doubleValue());
                    else if (obj0 instanceof String) {
                        stack.add(obj0.toString() + obj1.toString());
                    }
                }
            } else if (c == '-') {
                Object obj0 = stack.remove(selectedIndex);
                Object obj1 = stack.remove(selectedIndex);
                if (obj0 instanceof Number && obj1 instanceof Number)
                    stack.add(((Number) obj0).doubleValue() - ((Number) obj1).doubleValue());
                else if (obj0 instanceof String && obj1 instanceof String) {
                    stack.add(obj0.toString().replaceAll(obj1.toString(), ""));
                }
            } else if (c == '*') {
                Object obj0 = stack.remove(selectedIndex);
                Object obj1 = stack.remove(selectedIndex);
                if (obj0 instanceof Number && obj1 instanceof Number)
                    stack.add(((Number) obj0).doubleValue() * ((Number) obj1).doubleValue());
            } else if (c == '/') {
                Object obj0 = stack.remove(selectedIndex);
                Object obj1 = stack.remove(selectedIndex);
                if (obj0 instanceof Number && obj1 instanceof Number)
                    stack.add(((Number) obj0).doubleValue() / ((Number) obj1).doubleValue());
            } else if (c == 'a') {
                stack.add(selectedIndex, stack.remove(selectedIndex));
            } else if (c == 'c') {
                stack.add(scanner.nextLine());
            } else if (c == 'n') {
                if (stack.get(selectedIndex) instanceof String) {
                    stack.add(selectedIndex, Double.parseDouble(stack.remove(selectedIndex).toString()));
                } else if (stack.get(selectedIndex) instanceof Object[]) {
                    Object[] oldArray = (Object[]) stack.remove(selectedIndex);
                    Object[] newArray = new Object[oldArray.length];
                    for (int i = 0; i < oldArray.length; i++) {
                        newArray[i] = Double.parseDouble(oldArray[i].toString());
                    }
                    stack.add(selectedIndex, newArray);
                }
            } else if (c == '"') {
                String string = "\"";
                for (int cl0 = cl + 1; cl0 < content.length(); cl0++) {
                    string = string + content.charAt(cl0);
                    if (content.charAt(cl0) == '"') {
                        stack.add(string.substring(1, string.length() - 1));
                        cl = cl0;
                        break;
                    }
                }
            } else if (c == 's') {
                Object obj = stack.remove(selectedIndex);
                if (obj instanceof Double) {
                    Double dbl = (Double) obj;
                    if (dbl.doubleValue() == Math.floor(dbl)) {
                        stack.add(selectedIndex, "" + dbl.intValue() + "");
                    } else {
                        stack.add(selectedIndex, "" + dbl + "");
                    }
                }
            } else if (c == '╨') {
                cl++;
                char editmode = content.charAt(cl);
                if (editmode == '0') {
                    stack.add(selectedIndex, rot13(stack.remove(selectedIndex).toString()));
                } else if (editmode == '1') {
                    stack.add(selectedIndex,
                            new StringBuilder(stack.remove(selectedIndex).toString()).reverse().toString());
                } else if (editmode == '2') {
                    stack.add(selectedIndex, stack.remove(selectedIndex).toString().toLowerCase());
                } else if (editmode == '3') {
                    stack.add(selectedIndex, stack.remove(selectedIndex).toString().toUpperCase());
                }
            } else if (c == '_') {
                stack.add(selectedIndex, stack.get(selectedIndex));
            } else if (c == 'b') {
                stack.add(selectedIndex + 1, stack.remove(selectedIndex));
            } else if (c == 'd') {
                selectedIndex = stack.size() == 0 ? 0 : stack.size() - 1;
            } else if (c == 'm') {
                stack.add(stack.remove(selectedIndex));
            } else if (c == '@') {
                String number = "";
                for (int cl0 = cl + 1; cl0 < content.length(); cl0++) {
                    if (isNumber(content.charAt(cl0)))
                        number += content.charAt(cl0);
                    else {
                        cl = cl0 - 1;
                        selectedIndex = Integer.parseInt(number);
                        break;
                    }
                }
            } else if (c == 'w') {
                String number = "";
                for (int cl0 = cl + 1; cl0 < content.length(); cl0++) {
                    if (isNumber(content.charAt(cl0)))
                        number += content.charAt(cl0);
                    else {
                        cl = cl0 - 1;
                        Thread.sleep(Long.parseLong(number));
                        break;
                    }
                }
            } else if (c == '=') {
                Object obj0 = stack.remove(selectedIndex);
                Object obj1 = stack.remove(selectedIndex);
                stack.add(new Boolean(obj0.equals(obj1)));
            } else if (c == '~') {
                for (Object o : stack)
                    System.out.print(o);
                System.out.println();
            } else if (c == '²') {
                if (stack.get(selectedIndex) instanceof Double) {
                    Double dbl = (Double) stack.remove(selectedIndex);
                    stack.add(selectedIndex, dbl * dbl);
                } else if (stack.get(selectedIndex) instanceof Object[]) {
                    Object[] obj = (Object[]) stack.remove(selectedIndex);
                    Object[] newArray = new Object[obj.length];
                    for (int i = 0; i < obj.length; i++) {
                        newArray[i] = Math.pow((Double) obj[i], 2);
                    }
                    stack.add((Object[]) newArray);
                }
            } else if (c == '|') {
                String string = (String) stack.remove(selectedIndex);
                cl++;
                char splitChar = content.charAt(cl);
                stack.add((Object[]) string.split(splitChar + ""));
            } else if (c == '♀') {
                for (Object obj : (Object[]) stack.remove(selectedIndex)) {
                    stack.add(selectedIndex, obj);
                }
            } else if (c == '>') {
                whileStatements.add(new Integer(cl));
            } else if (c == '<') {
                cl = whileStatements.get(whileStatements.size() - 1);
            } else if (c == '!') {
                whileStatements.remove(whileStatements.size() - 1);
            } else if (c == '?') {
                if (stack.get(selectedIndex) instanceof Boolean) {
                    Boolean bool = (Boolean) stack.remove(selectedIndex);
                    if (bool == false) {
                        ifStatements++;
                        for (int cl0 = cl; cl0 < content.length(); cl0++) {
                            if (content.charAt(cl0) == '¿') {
                                ifStatements--;
                                cl = cl0;
                            }
                        }
                    }
                }
            } else if (c == 't') {
                break;
            } else if (c == '(') {
                stack.remove(selectedIndex);
            } else if (c == ':') {
                cl++;
                char charToVar = content.charAt(cl);
                vars.put(charToVar + "", stack.remove(selectedIndex));
            } else if (c >= 'A' && c <= 'Z') {
                stack.add(vars.get(c + ""));
            } else if (c == 'r') {
                stack.add(selectedIndex,
                        (double) new Random().nextInt(((Double) stack.remove(selectedIndex)).intValue() + 1));
            }
        }
        scanner.close();
    }

    public static String rot13(String input) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < input.length(); i++) {
            char c = input.charAt(i);
            if (c >= 'a' && c <= 'm')
                c += 13;
            else if (c >= 'A' && c <= 'M')
                c += 13;
            else if (c >= 'n' && c <= 'z')
                c -= 13;
            else if (c >= 'N' && c <= 'Z')
                c -= 13;
            sb.append(c);
        }
        return sb.toString();
    }

    public static boolean isNumber(char c) {
        return c >= '0' && c <= '9';
    }

}

Kullanması zor mu olmalı? : /
Hesap MakinesiFeline

0

Gökkuşağı (Not: Tercüman çok yakında)

Bu zorluğun süresinin dolduğunu biliyorum.

Gökkuşağı pek çok şeyin karışımı.

Rainbow, iki yığınlı (Like Brain-Flak) ve 8 yönlü ( N NE E SE S SW W NW) 2B yığın tabanlı bir dildir . 8 komut var:

  • 1, +, *, "Tam olarak 1+ yılında yaptığımı yap.
  • ! aktif yığını değiştirir.
  • > IP'yi saat yönünde çevirin.
  • , Bir karakter girin ve itin.
  • . Pop ve bir karakter çıktısı.

Ancak, kaynak kodundaki karakterler hemen çalıştırılmaz. Bunun yerine, [The Character in the source code]^[Top Of Stack]Collatz Conjecture olayıyla beslenir ve 1'e ulaşmak için attığı adımların sayısı ASCII tablosu tarafından bir karaktere dönüştürülür. Bu karakter daha sonra yürütülür.

  • 1'e ulaşmak için 127'den fazla adım gerekiyorsa, toplam adım sayısı 127'ye bölünür, hatırlatıcıyı alır ve hatırlatıcıyı bölüme ekler.

Programın başında, kaynak kod (son karakter hariç) yığının üstüne itilir.

IP kaynak kodunun kenarına ulaştığında sonlandırılır.

vahiy

n ve m, iki kayıtlıdır. Bir >komut yürütüldüğünde, m artırılır. Kıyamet, yalnızca m'nin n'yi aşması durumunda tetiklenir. Kıyamet gerçekleştiğinde:

  • Saat yönünde yerine saat yönünün tersine çevirin.
  • m 0 olur.
  • n yığının en üstünde olur. Ve sonra, yığın attı.

m başlangıçta sıfırdır ve n başlangıçta kaynak kodun son karakteridir.

Şifreleme

Herhangi bir işlemi yürüttükten sonra, kaynak kod şifrelenir. 1. karakterin ASCII'si bir artırılır, ikincisi bir artırılır, üçüncüsü iki artırılır, dördüncüsü artırılır, vb.


1
Bunun geçerli bir cevap olması için bir tercümana ihtiyacınız olduğuna eminim ...
Conor O'Brien

@ ConorO'Brien Bu meydan okuma süresi dolmuş olduğundan, bu sadece eğlence içindir. Yine de tercümanı sağlayacağım.
HighRadioactive

@HighlyRadioactive ... neredeyse bir ay önce dedin.
pppery
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.