En verimli küpleştirici


19

kübik olarak olarak herhangi bir kodu elle yazmak için çok sıkıcı. Zorluğunuz ASCII metnini Kübik kaynak koduna çevirmektir.

kübik olarak

Bu sadece Cubically hızlı bir halsiz olduğunu; depo daha eksiksiz rehber ve detaylar vardır.

Cubically, bir süre önce yazdığım, kullanmak acı verici olarak tasarlanmış bir esolang. İki adet bellek, 3x3x3 Rubik Küpü ve "not defteri" adı verilen bir kayıt içerir.

Hafıza

Dahili Rubik Küpü şu şekilde başlatılır:

   000
   000          top face
   000
111222333444    left, front, right, and back faces, respectively
111222333444
111222333444
   555
   555          down face
   555

Sağ yüzünde saat yönünde 90 ° dönüş yaptıktan sonra, bellek küpü şöyle görünecektir:

   002
   002
   002
111225333044
111225333044
111225333044
   554
   554
   554

Komutları

Tamsayı olmayan bir karakter varsayılan komutu ayarlar. Varsayılan komut yeniden ayarlanmadan önceki her tamsayı için komut bu tamsayı ile gerçekleştirilir. Örneğin, x524y312komut yerine olur xsonra komutu yerine 4, daha sonra, 2 ile, daha sonra 5 ile y2 daha sonra 1, daha sonra, 3 ile.

Komutları kullanan tamsayılar yüz dizinlerini temsil eder. Yani x0performans göstereceğini xUP (0-endeksli) yüzünde. x1icra ederdix böylece sol (1-endeksli), kumanda ve.

Herhangi bir komutun 6gerçekleştirilmesi bu komutu not defteri değerinde gerçekleştirir. 6 üzerinde herhangi bir tamsayı ile herhangi bir komutun gerçekleştirilmesi bir hataya neden olacaktır.

Aşağıda bazı örnek komutlar verilmiştir:

  • R1 - SAĞ yüzü saat yönünde 90 ° döndürün, böylece iç küp yukarıdaki ikinci örneğe benzeyecektir
  • R11 - SAĞ yüzü saat yönünde iki kez 90 ° döndürün, R2
  • +0 - UP yüzünün tüm değerlerini not defterine ekleyin
  • +000 - UP yüzünün tüm değerlerini üç kez not defterine ekleyin
  • @6 - varolmayan 6. endeksli yüzü (bellek) bir karakter olarak yazdır
  • %4 - GERİ yüzündeki tüm değerlerin toplamını bir tamsayı olarak yazdırır

Depoda komutların ve sözdiziminin tam bir listesi bulunmaktadır .

Meydan okuma

ASCII metnini girdi olarak alacak ve Cubically programını çıktı olarak yazdıracaksınız.

Örnekler ( buradan ve buradan çalınmış ):

Input -> Output
Hello, World! -> +53@6+1F2L2+0@6L2F2U3R3F1L1+2@66L3F3R1U1B3+0@6:4U1R1+00@6-000@6*0-4+000@6-00@6+2-000000@6-5+4000@6-00@6/0+00@6:0+0/0+00@6
1$2$3$4$5$6$7$8$9$10$ -> B1+2/2%6@4+00/0%6@4+00/1%6@4+21/1%6@4+30/0%6@4+22/1%6@4+22/1%6@4+40/1%6@4+52/1%6@4+42/1%6@4

kurallar

  • Programınız 100 testcasının çevirisini içeren bir sözlük içeremez.
  • Programınız 180 saniyeden kısa sürede bitmelidir (haftalar süren kaba kuvvet programları yoktur).
  • Programınız 180 saniyeden kısa sürede biten geçerli bir Kübik kod çıktısı almalıdır.
  • Test sürücüsüyle uğraşmak istemiyorsanız, programınız standart giriş üzerinden giriş alacaktır.
  • Programınız, çalıştırıldığında programınızın girdisinden başka bir şey üretmeyen Kübik kod çıktısı almalıdır. ಠ_ಠ

puanlama

Programınızı, yalancı metin uzunluğu olan 100 sahte dizeyle test edeceksiniz. (Bunu sizin için yapacak bir bash betiği sağlanmıştır.) İşte nasıl puan vereceksiniz:

  • Çıktı programının uzunluğu o olsun .
  • Girdi dizesinin uzunluğu l olsun .
  • Izin vermek r değişkeni o / l sonucu olsun .
  • Tüm r'lerin ortalamasını bulun : (r 1 + r 2 + r ... + r 100 ) / 100 .

Bu komut dosyasıyla test edin. Talimatlara uygun olarak değiştirmeniz gerekir. Program, çıktının Kübik kod geçerli olup olmadığını denetlemediğini unutmayın. Senaryoyu çalıştıramazsan yardımcı olabilirim. Kübik sohbet odasında bana ping at .



" @6- varolmayan 6. endeksli yüzün (not defteri) toplamını bir karakter olarak yazdır" daha doğru olur mu? Mı %4da bir miktar? Are +komutlar toplamı yüzü sonra ... tüm değerleri veya bu ekleme?
Jonathan Allan

@JonathanAllan @6/ %6doğrudan not defteri değerini bir karakter / tamsayı olarak yazdırır. @x/ %x(burada x varolan herhangi bir yüzdür), x-indexed yüzüne tüm değerleri ekler ve toplamı bir karakter / tamsayı olarak yazdırır. +belirtilen yüzdeki tüm değerleri kayıt defterine ekler.
MD XF

Ah, nedense not defterini 9 değere sahip olarak düşünüyordum.
Jonathan Allan

Yanıtlar:


4

C ++ 11, Puan : 6.37

#include <iostream>
#include <vector>
#include <array>
#include <limits>
#include <algorithm>

const int inf = std::numeric_limits<int>::max(),
maxDiff = 128, nFace = 6;
std::array<int, maxDiff+1> plusvalue, totalvalue, plustrace, totaltrace;
std::array<int, nFace> input;

void prtrace(int value) {
    while (value) {
        std::cout << plustrace[value];
        value -= input[plustrace[value]];
    }
}

void prexpr(int i) {
    char xorwt = 0;
    if (i < 0) {
        xorwt = '+' ^ '-';
        i = -i;
    }
    if (totalvalue[i] != 0 && totalvalue[i] != inf) {
        std::cout << (char)('+' xor xorwt);
        prtrace(totaltrace[i]);
        if (totaltrace[i] != i) {
            std::cout << (char)('-' xor xorwt);
            prtrace(totaltrace[i] - i);
        }
    }
}

int main() {
    std::cout << "RU";
    input = {6, 15, 27, 26, 19, 42};
    std::cin >> std::noskipws;

    std::fill(plusvalue.begin(), plusvalue.end(), inf);
    plusvalue[0] = 1; // '+'
    for (int i = 0; i < nFace; ++i) { // knapsack, each value repeated inf times
        int val = input[i];
        if (val == 0) continue;
        for (int p = 0; p <= maxDiff - val; ++p) {
            if (plusvalue[p] != inf && plusvalue[p + val] > plusvalue[p] + 1) {
                plusvalue[p + val] = plusvalue[p] + 1;
                plustrace[p + val] = i;
            }
        }
    }
    for (int p = 0; p <= maxDiff; ++p) totalvalue[p] = plusvalue[p], totaltrace[p] = p;
    totalvalue[0] = 0;
    for (int sub = 1; sub <= maxDiff; ++sub) {
        if (plusvalue[sub] == inf) continue;
        for (int p = 0; p <= maxDiff - sub; ++p) {
            if (plusvalue[p+sub] != inf && totalvalue[p] > plusvalue[p+sub] + plusvalue[sub]) { // include '+'s
                totalvalue[p] = plusvalue[p+sub] + plusvalue[sub];
                totaltrace[p] = p+sub;
            }
        }
    }

//    // Note: plustrace[x] = i<=nFace : plustrace[x-input[i]] + 1 = plustrace[x]
//    long long sum = 0;
//    for (int i = 0; i <= maxDiff; ++i) {
//        sum += totalvalue[i];
//        std::cout << i << '\t' << totalvalue[i] << '\t';
//        prexpr(i);
//        std::cout << '\n';
//    }
//
//    std::cout << "_______________________________\n\nAverage = " << sum / (maxDiff + 1.) << '\n';

// RU 3.98131

    char ch;
    int cur = 0;
    while (std::cin >> ch) {
        int diff = ch - cur;
        prexpr(diff);
        std::cout << "@6";
        cur += diff; // cur = ch
    }
}

/*
RU 3.98131
*/

Çevrimiçi deneyin! (ASCII'den Kübik kod üret) ve (Kübik kod çalıştır)

Açıklama:

  • Önce program "RU" yazdırır, bu da yüzün toplamını {0,9,18,27,36,45}oluşturur {6, 15, 27, 26, 19, 42}. Bu yüz toplamının faydalı olmasını sağlayan şey, gcd'nin 1 olmasıdır, bu nedenle Bézout'un kimliği dile bu sayıların toplamından (veya farkından) herhangi bir sayı oluşturmanın bir yolu vardır .
  • Bir sonraki karakter ise nedenle, chve geçerli not defteri değer n, o zaman izin d = ch - n, biz formda cubically komutları yürütebilirsiniz +{digits from 0 to 5}-{digits from 0 to 5}not defteri değeri olur, öyle ki ch. Sonra sadece yürütün%6 not defteri değerini yazdırmak için .
  • İfade etmek en etkili yolu bulmak için dyüz toplamı sette numaralarının toplamı / fark olarak, ben 0'dan 128. Ör için tüm sayılar için Sırt Çantası algoritma kullanıyoruz d=1programı alır, 27 - 26 = 1o yazdırır, böylece +2-3olan 27 - 26 = 1. Girdi ile program çalıştırıldığında görülebilir abc, program çıktı

    RU + 4333 @ 6 + 2-3 @ 6 + 2-3 @ 6


Vay, iyi iş çıkardın! Knapsack algoritması sanırım aradığımız şeydi.
TehPers

Dil güncellemeleri nedeniyle, @dolaylı olarak arayarak daha iyi bir puan @6alabileceğinizi unutmayın @- her durumda kısaltılabilir .
MD XF

17

Lua, Puan : 85.91 13.50 13.20 12.70 9.41 9.32 9.83 9.66 9.12 9.06 8.03 (Ortalama)

-- Get input
local inp = io.read("*a")

local out = ""
local faces = { [5] = 45, [4] = 36, [3] = 27, [2] = 18, [1] = 9 }
local lastChar = nil

-- Mode the program is in
-- 2 = not set (needs :), 1 = just set (needs +), 0 = normal
local mode = 1;
for i = 1, inp:len() do
  -- Character value at current position
  local c = string.byte(inp, i)

  if c == lastChar then
    -- Repeat character
    out = out .. "6"
  elseif c % 9 == 0 and c <= 45 then
    if #out == 0 then
      out = out .. "@"
    end
    out = out .. (c / 9)
  else
    local c2 = c

    -- Handle if difference from lastChar is divisible by 9
    if lastChar and (c - lastChar) % 9 == 0 then
      local difference = c - lastChar
      if difference > 0 then
        out = out .. "+"
      else
        out = out .. "-"
        difference = difference * -1
      end

      for index = 5, 1, -1 do
        local face = faces[index]
        while difference >= face do
          difference = difference - face
          out = out .. index
        end
      end
      c = 0
    end

    -- Handle anything not divisible by 9
    local extra = c % 9
    if extra > 0 then
      -- Try to optimize by dividing by 9, if possible
      if lastChar and math.floor(lastChar / 9) == extra then
        out = out .. "/1"
        mode = 1
        extra = 0
      else
        while extra > 0 do
          local n = extra > 5 and 5 or extra

          if mode == 2 then
            out = out .. ":"
            mode = 1
          elseif mode == 1 then
            out = out .. "+"
            mode = 0
          end
          out = out .. n
          extra = extra - n
        end
        out = out .. "/1"
        mode = 1
      end

      c = c - (c % 9)
    end

    -- Handle anything divisible by 9
    for index = 5, 1, -1 do
      local face = faces[index]
      while c >= face do
        if mode == 2 then
          out = out .. ":"
          mode = 1
        elseif mode == 1 then
          out = out .. "+"
          mode = 0
        end
        c = c - face
        out = out .. index
      end
    end

    out = out .. "@6"
    lastChar = c2
  end

  mode = 2
end
print(out)

Çevrimiçi deneyin!

Tamam, artık bunu optimize edebileceğimi sanmıyorum.

Bu sürüm, her karakter boyunca yinelenerek c% 9 (burada c karakterin ondalık değeri) :5+2/1eklenir ve ardından bu yüzün değerini ekleyerek 9'a bölünebilir parçalar eklenir. Örneğin: 2 eklediği :2/1+551@"e" yi yazdırmak için 99 (9 * (5 + 5 + 1) veya 9 * 11) ekler ve çıktıyı yazdırır. Giriş ile okunur .:2/1+551@io.read()

Optimizasyonlar arasında, karakterler arasındaki fark 9'un katları ise baskıdan sonra doğrudan ekleme / çıkarma, c% 9'u sıfırdan ayarlamak yerine geçerli değeri bölme ve mevcut değeri yeniden hesaplamak yerine tekrar yazarak karakterleri tekrarlama yer alır. Ayrıca, Kamil'in hedef değeri içeren herhangi bir yüzü anında basma yöntemini ve MD XF'nin :başlangıçta kullanılmaması önerisini uyguladım , bunun yerine sadece bir ile başladım +.


1
Her zaman kendi sorularınıza ve cevaplarınıza yorum yapabilirsiniz, ancak henüz genel yorum ayrıcalıklarına sahip değilsiniz. Bunun gibi cevaplarla uzun
sürmemeliyiz

2
@MDXF Pek iyi değilim: P
Kamil Drakari

1
Değişebilirsin local inp = io.read()için local inp = io.read("*all"). Bu sorunu çözer.
MD XF

1
Başka bir olası optimizasyon - not defteri 0'da başladığından, aslında çıktı almanıza gerek yoktur, örneğin :5+124, bunun yerine sadece yazabilirsiniz +5124, bu da doğru ayarladığınızda muhtemelen puanı biraz düşürür.
MD XF

1
Yanıtınızı örtülü yüz dönüşleri gibi son Kübik güncellemelerin bazılarını destekleyecek şekilde değiştirirseniz muhtemelen daha iyi bir puan alırsınız.
MD XF

16

Kısmen , Puan : 86.98

U3D1R3L1F3B1U1D3~:7+1(-1@3(-1%1)6:1+3111@6%1-31111+004@6:1+11111%6:1+45@6:1-1%6~:7+1)6 

Çevrimiçi deneyin!

Görünen o ki, tek ihtiyacınız olan koşullu döngüler, 1'e eşit bir yüz ve tutarlı Girdi Sonu davranışı.

U3D1R3L1F3B1U1D3     set LEFT face sum to 1
~:7                  read input, set notepad to input
+1                   add 1 to notepad

(                    open loop that can always be jumped to
 -1                   subtract 1 from notepad
 @3                   print RIGHT face (ASCII 43 '+')

            ##   the following mechanism gets the output program's   ##
            ##   notepad to the current inputted ASCII value:        ##

 (                    open loop that can always be jumped to
  -1                   subtract 1 from notepad
  %1                   print '1'
 )6                   jump back to loop while notepad is nonzero

            ##   the following mechanism prints "/1@6:1"             ##

 :1+3111@6            set notepad to 47,    print (ASCII 47 '/')
 %1                   print LEFT face       print (integer '1')
 -31111+004@6         set notepad to 64,    print (ASCII 64 '@')
 :1+11111%6           set notepad to 6,     print (integer 6)
 :1+45@6              set notepad to 58,    print (ASCII 58 ':')
 :1-1%6               set notepad to 0,     print (integer 1)

 ~                    read input
 :7+1                 set notepad to input plus 1, so EOF changes to zero
)6                    loop if notepad is truthy

SOL yüzün eklenmesi / çıkarılması EOF okunduğunda döngünün bitmesini sağlamaktır.


2
Sen var var şaka olarak. Bu inanılmaz.
MD XF

Oh hey, hatta orijinal C # cevabımdan daha iyi bir skoru var!
Kamil Drakari

Dil güncellemeleri nedeniyle, @dolaylı olarak arayarak daha iyi bir puan @6alabileceğinizi unutmayın @- her durumda kısaltılabilir .
MD XF

9

C # (.NET Çekirdek) , Puan: 129.98 11.73 10.82 9.62 10.33 10.32 10.20

MD XF'in tekrarlanan karakter @6666...yerine @6@6@6@6...üstün önerisi ve üstün başlatma sırası -1.2 puan

static void Main()
{
	List<byte> input = new List<byte>();
            int inChar = Console.Read();
            while (inChar != -1)
            {
                input.Add((byte)inChar);
                inChar = Console.Read();
            }


            Console.Write("U3D1R3L1F3B1U1D3");
            byte[] sides = new byte[] { 20, 1, 14, 43, 24, 33 };

            byte currentChar = 0;

   	    if(currentChar == input[0] || sides.Contains(input[0])) Console.Write("@");

            foreach (byte character in input)
            {
		if (currentChar == character)
		{
			Console.Write("6");
			continue;
		}
		
		if (sides.Contains(character))
		{
			Console.Write(Array.IndexOf(sides, character));
			continue;
		}
                if (currentChar < character)
                {
                    Console.Write("+");
                    while (currentChar < character)
                    {
                        byte nextAdd = sides.Where(s => s + currentChar <= character).Max();
                        currentChar = (byte)(currentChar + nextAdd);
                        Console.Write(Array.IndexOf(sides, nextAdd));
                    }
                }

                if (currentChar > character)
                {
                    Console.Write("-");
                    while (currentChar > character)
                    {
                        byte nextSub = sides.Where(v => currentChar - v >= character).Max();
                        currentChar = (byte)(currentChar - nextSub);
                        Console.Write(Array.IndexOf(sides, nextSub));
                    }
                }

                Console.Write("@6");
            }
}

Çevrimiçi deneyin!

En yeni versiyonum aslında küpün bazı manipülasyonlarını yapıyor! Yaşasın!

İlk önce Console.Write, bu küpü yaratan sabit bir manipülasyon MD XF var:

   242
   202
   242
000131555313
010121535343
000131555313
   424
   454
   424

Bu küpün önemi, kenarlarından birinin toplamı 1 olan Not Defteri'nin dokuz kattan daha küçük bir ölçekte manipülasyonuna izin vermesidir ve özellikle her karakteri sıfırdan başlamak zorunda kalmak yerine göreceli hareketi basitleştirir; bu algoritmada karakterler arasında en kısa yolu almak için toplama ve çıkarma kullanılır.

MD XF'nin başlatma sürümü, taraf 2'nin toplamının 14 olmasına neden olur ve bu da 14 ve 20 arasındaki ASCII mesafeleri için birçok bayt çıkış tasarrufu sağlar.

Artık dahili yeni satırlarla girişleri işleyebilir, Console.Read () Dosya sonuna kadar ayrı ayrı karakterler alır; girişi olması gereken TIO bağlantısına bakın

Hello, 
World!

ASCII değeri zaten bir tarafta varsa, bir karakterin hemen çıktısını alarak bir noktanın birkaç kısmını tıraş etti.

Test Komut Dosyası MDXF izniyle


Buraya önceki gönderim ve açıklama:

Bu biraz sıkıcı ama söyleyebildiğim kadarıyla işe yarıyor. Kuşkusuz sadece denedimHello, World! ama çıktıyı TIO Cubically yorumlayıcısında çalıştırdım ve çıktı "Merhaba, Dünya!" bu yüzden işe yaradığını düşündüm.

Küpü gerçekten manipüle etmek yerine, not defteri, her bir karakter için doğru değere sahip olana kadar 1 yüzün (9) toplamıyla art arda arttırılır, daha sonra yazdırılır.


Yorumlar uzun tartışmalar için değildir; bu sohbet sohbete taşındı .
Martin Ender

@MartinEnder Bunları mevcut sohbet odasına taşıyabilir misiniz ?
MD XF

@MDXF Yapabilirdim ama bu sohbet odasında tamamen yer ve bağlam dışında olup olmadıklarını söyleyemem.
Martin Ender

@MartinEnder Yorumlar sohbet odasından daha eskidir, bu yüzden transkriptte geri döneceklerdi, değil mi?
MD XF

Yapacaklardı. Teşekkürler, mesajları taşıyacağım.
Martin Ender
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.