Cubifier paling efisien


19

Cubically terlalu membosankan untuk secara manual menulis kode apa pun. Tantangan Anda adalah menerjemahkan teks ASCII menjadi kode sumber Cubically.

Secara kubik

Ini hanyalah perombakan cepat dari Cubically; yang repositori memiliki panduan yang lebih lengkap dan detail.

Secara kubik adalah esolang yang saya tulis beberapa waktu lalu, dirancang untuk menyakitkan untuk digunakan. Ini berisi dua buah memori, Rubik's Cube 3x3x3 dan register yang disebut "notepad".

Penyimpanan

Kubus Rubik internal diinisialisasi seperti ini:

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

Setelah melakukan putaran 90 ° searah jarum jam pada wajah kanan, kubus memori akan terlihat seperti ini:

   002
   002
   002
111225333044
111225333044
111225333044
   554
   554
   554

Perintah

Karakter non-integer menetapkan perintah default. Untuk setiap integer sebelum perintah default ditetapkan sekali lagi, perintah dilakukan dengan integer itu. Misalnya, x524y312akan melakukan perintah xdengan 5, lalu dengan 2, lalu dengan 4, kemudian melakukan perintah ydengan 3, lalu dengan 1, lalu dengan 2.

Bilangan bulat yang digunakan perintah mewakili indeks wajah. Jadi x0akan tampil xdi wajah UP (0-diindeks). x1akan tampil xdi wajah KIRI (1-diindeks), dan sebagainya.

Melakukan perintah apa pun dengan 6akan melakukan perintah itu pada nilai notepad. Melakukan perintah apa pun dengan bilangan bulat apa pun di atas 6 akan menghasilkan kesalahan.

Berikut adalah beberapa contoh perintah:

  • R1 - putar wajah KANAN 90 ° searah jarum jam sehingga kubus internal akan terlihat seperti contoh kedua di atas
  • R11 - putar wajah KANAN searah jarum jam 90 ° dua kali, identik dengan R2
  • +0 - tambahkan semua nilai wajah UP ke notepad
  • +000 - tambahkan semua nilai wajah UP ke notepad tiga kali
  • @6 - cetak wajah yang diindeks 6 tidak ada (memori) sebagai karakter
  • %4 - cetak jumlah semua nilai pada wajah BACK sebagai integer

Daftar lengkap perintah dan sintaks tersedia di repositori .

Tantangan

Anda akan mengambil teks ASCII sebagai input dan mencetak program Cubically sebagai output.

Contoh (dicuri dari sini dan sini ):

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

Aturan

  • Program Anda mungkin tidak mengandung kamus yang berisi terjemahan untuk 100 testcases.
  • Program Anda harus selesai dalam waktu kurang dari 180 detik (tidak ada program kekerasan yang membutuhkan waktu berminggu-minggu).
  • Program Anda harus menampilkan kode Cubically valid yang selesai dalam waktu kurang dari 180 detik.
  • Program Anda akan mengambil input melalui input standar, kecuali jika Anda ingin mengacaukan dengan driver tes.
  • Program Anda harus menampilkan kode yang tidak menghasilkan apa-apa selain input program Anda ketika dijalankan. ಠ_ಠ

Mencetak gol

Anda akan menguji program Anda dengan 100 pseudorandom string dengan panjang pseudorandom. (Skrip bash disediakan yang akan melakukan ini untuk Anda.) Berikut adalah skor Anda:

  • Biarkan panjang program output menjadi o .
  • Biarkan panjang string input menjadi l .
  • Biarkan variabel r menjadi hasil dari o / l .
  • Temukan rata-rata semua r : (r 1 + r 2 + r ... + r 100 ) / 100 .

Uji dengan skrip ini. Anda harus memodifikasinya seperti yang diperintahkan. Perhatikan bahwa program tidak memeriksa apakah outputnya kode Cubically valid. Jika skrip tidak berfungsi, saya dapat membantu. Ping saya di ruang obrolan Cubically .



Apakah " @6- mencetak jumlah wajah tanpa indeks 6 yang tidak ada (karakter)" menjadi lebih akurat? Apakah %4juga jumlah? Apakah +perintah menjumlahkan wajah lalu menambahkannya ke semua nilai atau ...?
Jonathan Allan

@JonathanAllan @6/ %6langsung mencetak nilai notepad sebagai karakter / integer. @x/ %x(di mana x adalah wajah yang ada) menambahkan semua nilai pada xwajah -indexed dan mencetak penjumlahan sebagai karakter / integer. +menambahkan semua nilai pada wajah yang ditentukan ke register.
MD XF

Ah, entah kenapa aku memikirkan notepad itu juga memiliki 9 nilai.
Jonathan Allan

Jawaban:


4

C ++ 11, Skor : 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
*/

Cobalah online! (menghasilkan kode Cubically dari ASCII) dan (jalankan kode Cubically)

Penjelasan:

  • Pertama program mencetak "RU", yang membuat jumlah wajah dari {0,9,18,27,36,45}ke {6, 15, 27, 26, 19, 42}. Apa yang membuat set jumlah wajah berguna adalah bahwa gcd adalah 1, jadi dengan identitas Bézout ada cara untuk membangun angka ddari jumlah (atau perbedaan) dari angka-angka itu.
  • Oleh karena itu, jika karakter berikutnya adalah chdan nilai notepad saat ini adalah n, maka mari d = ch - n, kita dapat menjalankan perintah Cubically dalam bentuk +{digits from 0 to 5}-{digits from 0 to 5}sehingga nilai notepad menjadi ch. Kemudian jalankan %6untuk mencetak nilai notepad.
  • Untuk menemukan cara paling efisien untuk menyatakan dsebagai jumlah / perbedaan angka dalam set jumlah wajah, saya menggunakan algoritma Knapsack untuk semua angka dari 0 hingga 128. Misalnya, untuk d=1, program didapat 27 - 26 = 1, jadi ia mencetak +2-3, yaitu 27 - 26 = 1. Yang bisa dilihat saat menjalankan program dengan input abc, output program

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


Woah, kerja bagus! Algoritma Knapsack adalah apa yang kami cari, saya kira.
TehPers

Perhatikan bahwa karena pembaruan bahasa, Anda dapat memperoleh skor yang lebih baik melalui panggilan @secara implisit - @6dapat disingkat menjadi @semua kasus.
MD XF

17

Lua, Skor : 85.91 13.50 13.20 12.70 9.41 9.32 9.83 9.66 9.12 9.06 8.03 (Rata-rata)

-- 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)

Cobalah online!

Oke, saya rasa saya tidak bisa mengoptimalkan ini lagi.

Versi ini berulang melalui setiap karakter, menambahkan c% 9 (dengan c adalah nilai desimal karakter) dengan melakukan :5+2/1, lalu menambahkan bagian-bagian yang dapat dibagi dengan 9 dengan menambahkan nilai wajah itu. Misalnya: :2/1+551@untuk mencetak "e", di mana :2/1menambahkan 2, +551menambahkan 99 (9 * (5 + 5 + 1), atau 9 * 11), dan @mencetak hasilnya. Input dibaca dengan io.read().

Optimalisasi mencakup penambahan / pengurangan langsung setelah pencetakan jika perbedaan antara karakter adalah kelipatan dari 9, membagi nilai saat ini jika memungkinkan daripada pengaturan c% 9 dari awal, dan mengulangi karakter dengan mencetak nilai saat ini lagi daripada menghitung ulang. Selain itu, saya telah menerapkan metode Kamil untuk langsung mencetak wajah apa pun yang sudah berisi nilai target, dan saran MD XF untuk tidak menggunakan :di awal, tetapi sebaliknya hanya mulai dengan a +.


1
Anda selalu dapat mengomentari pertanyaan dan jawaban Anda sendiri, tetapi Anda belum memiliki hak komentar umum yang umum. Seharusnya tidak lama dengan jawaban seperti ini (atau, lebih mungkin, hanya jawaban ini sekali lagi beberapa orang melihatnya)
Kamil Drakari

2
@ MDXF Saya tidak begitu baik: P
Kamil Drakari

1
Anda bisa berubah local inp = io.read()menjadi local inp = io.read("*all"). Itu memperbaiki masalah.
MD XF

1
Kemungkinan optimasi lain - karena notepad dimulai dari 0, Anda sebenarnya tidak perlu menampilkan, misalnya :5+124, Anda hanya bisa menulis +5124, yang mungkin akan mendapatkan skor sedikit jika Anda mengubah dengan benar.
MD XF

1
Anda kemungkinan akan mendapatkan skor yang lebih baik jika Anda mengubah jawaban Anda untuk mendukung beberapa pembaruan Cubically terbaru, seperti perubahan wajah implisit.
MD XF

16

Secara kubik , Skor : 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 

Cobalah online!

Ternyata, yang Anda butuhkan adalah loop kondisional, wajah sama dengan 1, dan perilaku End-Of-Input yang konsisten.

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

Menambahkan / mengurangi wajah LEFT adalah untuk mendapatkan loop untuk mengakhiri ketika EOF dibaca.


2
Anda telah mendapat untuk menjadi bercanda. Ini luar biasa.
MD XF

Oh hei, itu bahkan memiliki skor lebih baik daripada jawaban C # asli saya!
Kamil Drakari

Perhatikan bahwa karena pembaruan bahasa, Anda dapat memperoleh skor yang lebih baik melalui panggilan @secara implisit - @6dapat disingkat menjadi @semua kasus.
MD XF

9

C # (.NET Core) , Skor: 129.98 11.73 10.82 9.62 10.33 10.32 10,20

-1.2 poin dari saran MD XF untuk digunakan @6666...alih-alih @6@6@6@6...untuk pengulangan karakter, dan urutan inisialisasi superior

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");
            }
}

Cobalah online!

Versi terbaru saya sebenarnya melakukan manipulasi kubus! Yay!

Yang pertama Console.Writeada manipulasi tetap yang berhasil dilakukan MD XF yang menciptakan kubus ini:

   242
   202
   242
000131555313
010121535343
000131555313
   424
   454
   424

Arti penting dari kubus ini adalah bahwa salah satu sisinya memiliki jumlah 1, yang memungkinkan manipulasi Notepad pada skala yang lebih kecil dari kelipatan sembilan, dan khususnya menyederhanakan gerakan relatif daripada perlu mulai dari nol setiap karakter; dalam algoritme ini, penjumlahan dan pengurangan digunakan untuk mengambil jalur terpendek antar karakter.

Inisialisasi versi MD XF menyebabkan sisi 2 memiliki jumlah 14, yang menghemat banyak byte output untuk jarak ASCII antara 14 dan 20.

Sekarang dapat menangani input dengan baris baru internal, Console.Read () mendapatkan karakter individual hingga Akhir File; lihat tautan TIO yang seharusnya memiliki input

Hello, 
World!

Mencukur beberapa pecahan suatu titik dengan segera mengeluarkan karakter jika nilai ASCII-nya kebetulan sudah ada di satu sisi.

Test Script milik MDXF


Pengajuan sebelumnya di sini dan penjelasannya:

Ini agak membosankan, tetapi sejauh yang saya tahu itu berhasil. Memang saya hanya mencoba Hello, World!tetapi saya menjalankan output di TIO Cubically interpreter dan mengeluarkan "Hello, World!" jadi saya menganggap itu berhasil.

Daripada benar-benar memanipulasi kubus sama sekali, notepad hanya bertambah dengan jumlah dari 1 wajah (9) berulang kali hingga memiliki nilai yang tepat untuk setiap karakter, kemudian mencetaknya.


Komentar bukan untuk diskusi panjang; percakapan ini telah dipindahkan ke obrolan .
Martin Ender

@ MartinEnder Bisakah Anda memindahkan mereka ke chatroom yang ada ?
MD XF

@ MDXF saya bisa tapi saya tidak tahu apakah mereka benar-benar keluar dari tempatnya dan konteks di chatroom itu.
Martin Ender

@MartinEnder Komentar lebih tua dari ruang obrolan, jadi mereka akan muncul jauh di belakang dalam transkrip, benar?
MD XF

Mereka akan. Terima kasih, saya akan memindahkan pesannya.
Martin Ender
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.