Найефективніший кубіфікатор


19

Кубічно занадто нудно, щоб вручну писати будь-який код. Ваша задача полягає в тому, щоб перевести текст ASCII в кубічно вихідний код.

Кубічно

Це лише швидкий збіг кубічно; сховище має більш повне керівництво і деталі.

Кубічно це езоланг, про який я писав деякий час тому, призначений для болючого використання. Він містить два фрагменти пам'яті, куб Рубіка 3x3x3 та реєстр, який називається "блокнот".

Пам'ять

Внутрішній куб Рубіка ініціалізується так:

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

Після виконання повороту на 90 ° за годинниковою стрілкою на правому обличчі куб пам'яті виглядатиме так:

   002
   002
   002
111225333044
111225333044
111225333044
   554
   554
   554

Команди

Нецілий символ задає команду за замовчуванням. Для кожного цілого числа перед тим, як знову встановити команду за замовчуванням, команда виконується з цим цілим числом. Наприклад, x524y312виконували б команду xз 5, потім з 2, потім з 4, потім виконували команду yз 3, потім з 1, потім з 2.

Цілі числа, які використовують команди, представляють індекси обличчя. Так x0буде виконувати xна обличчі UP (0-індексований). x1буде виконувати xна лівому (1-індексованому) обличчі тощо.

Виконуючи будь-яку команду з 6, виконайте цю команду у значенні блокнота. Виконання будь-якої команди з будь-яким цілим числом понад 6 призведе до помилки.

Ось кілька прикладів команд:

  • R1 - поверніть ВПРАВО лицем за годинниковою стрілкою на 90 °, щоб внутрішній куб виглядав як другий приклад вище
  • R11 - поверніть ВПРАВО лицем за годинниковою стрілкою на 90 ° двічі, ідентично R2
  • +0 - додайте всі значення лицьової панелі UP в блокнот
  • +000 - додайте всі значення лицьової панелі UP до блокноту тричі
  • @6 - друкуйте неіснуюче 6-е індексоване обличчя (пам'ять) як символ
  • %4 - друкувати суму всіх значень на обличчі BACK як ціле число

Повний список команд та синтаксису доступний у сховищі .

Виклик

Ви візьмете текст ASCII як вхідний файл і будете друкувати кубічно програму як вихід.

Приклади (вкрадені звідси і тут ):

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

Правила

  • Ваша програма може не містити словник, що містить переклади для 100 тестів.
  • Ваша програма повинна закінчитися менш ніж за 180 секунд (жодних програм, які тривають тижні).
  • Ваша програма повинна вивести дійсний кубічно код, який закінчується менш ніж за 180 секунд.
  • Ваша програма буде приймати введення через стандартний вхід, якщо ви не хочете возитися з тестовим драйвером.
  • Ваша програма повинна виводити кубічно код, який не створює нічого, крім введення програми під час запуску. ಠ_ಠ

Оцінка балів

Ви протестуєте свою програму зі 100 псевдовипадкових рядків псевдовипадкової довжини. (Наведено сценарій bash, який зробить це за вас.) Ось як ви оцінюєте:

  • Нехай довжина вихідної програми буде o .
  • Нехай довжина вхідного рядка дорівнює l .
  • Нехай змінна r є результатом o / l .
  • Знайдіть середнє значення всіх r : (r 1 + r 2 + r ... + r 100 ) / 100 .

Тест за допомогою цього сценарію. Вам доведеться модифікувати його згідно з інструкціями. Зауважте, що програма не перевіряє, чи дійсний вихідний код кубічно. Якщо ви не можете змусити сценарій працювати, я можу допомогти. Пінг мене в кімнаті для кубічного чату .



Буде " @6- надрукувати суму неіснуючого 6-го індексованого обличчя (блокнота) як символу" було б точніше? Є %4також сума? Чи +додається команда підсумовувати всі значення та ...?
Джонатан Аллан

@JonathanAllan @6/ %6просто безпосередньо друкує значення блокнота як символ / ціле число. @x/ %x(де x - будь-яке існуюче обличчя) додає всі значення на x-вкладене обличчя та друкує суму як символ / ціле число. +додає в регістр усі значення на вказаній обличчі.
MD XF

Ах, я чомусь думав про блокнот як про 9 значень.
Джонатан Аллан

Відповіді:


4

C ++ 11, оцінка : 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
*/

Спробуйте в Інтернеті! (генерувати кубічно код з ASCII) та (запустити кубічно код)

Пояснення:

  • Спочатку програма друкує «RU», які становлять суму особи від {0,9,18,27,36,45}до {6, 15, 27, 26, 19, 42}. Завдяки цьому набір номінальної суми є корисним у тому, що gcd дорівнює 1, тож за особою Безута існує спосіб побудувати будь-яке число dіз суми (або різниці) цих чисел.
  • Тому, якщо наступним знаком є chпоточне значення блокнота n, тоді нехай d = ch - nми можемо виконати команди кубічно у +{digits from 0 to 5}-{digits from 0 to 5}такій формі , якою стає значення блокнота ch. Потім просто виконати, %6щоб надрукувати значення блокнота.
  • Щоб знайти найбільш ефективний спосіб виразити dяк суму / різницю чисел у наборі номінальної суми, я використовую алгоритм Knapsack для всіх чисел від 0 до 128. Наприклад, d=1програма отримує 27 - 26 = 1, так що вона друкує +2-3, що є 27 - 26 = 1. Що можна побачити під час запуску програми з введення abc, виведення програми

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


Вау, чудова робота! Я думаю, алгоритм Knapsack - це те, що ми шукали.
TehPers

Зауважте, що завдяки оновленням мови ви можете отримати кращу оцінку, невірно зателефонувавши @- @6її можна скоротити до @всіх випадків.
MD XF

17

Луа, Оцінка : 85,91 13,50 13,20 12,70 9,41 9,32 9,83 9,66 9,12 9,06 8,03 (середній)

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

Спробуйте в Інтернеті!

Гаразд, я не думаю, що вже вдається оптимізувати це.

Ця версія повторюється через кожен символ, додаючи c% 9 (де c - десяткове значення символу), виконуючи :5+2/1наступні дії , а потім додає частини, розділені на 9, додаючи значення цього обличчя. Наприклад: :2/1+551@для друку "e", де :2/1додається 2, +551додається 99 (9 * (5 + 5 + 1) або 9 * 11) і @друкується вихід. Введення зчитується за допомогою io.read().

Оптимізація включає безпосередньо додавання / віднімання після друку, якщо різниця між символами кратна 9, ділення поточного значення, якщо це можливо, а не встановлення c% 9 з нуля, і повторення символів, повторне друкування поточного значення, а не перерахунок його. Крім того, я реалізував метод Каміля негайно надрукувати будь-яке обличчя, яке вже містить цільове значення, та пропозицію MD XF не використовувати :на початку, а замість цього просто розпочати з +.


1
Ви завжди можете коментувати власні питання та відповіді, але ви ще не зовсім до загальних привілеїв для коментарів. Не слід довго відповідати подібними (або, що, швидше за все, просто ця відповідь, коли ще кілька людей бачать її)
Каміль Дракарі

2
@MDXF Я не зовсім такий приємний: P
Kamil Drakari

1
Ви можете змінити local inp = io.read()на local inp = io.read("*all"). Це вирішує проблему.
MD XF

1
Інша можлива оптимізація - оскільки блокнот починається з 0, вам насправді не потрібно виводити, наприклад :5+124, натомість ви можете просто записати +5124, що, ймовірно, трохи знизить рахунок, якщо ви налаштуєте його правильно.
MD XF

1
Ви, швидше за все, отримаєте кращу оцінку, якщо зміните свою відповідь на підтримку деяких останніх оновлень, що стосуються кубічних змін, наприклад, неявних витків обличчя.
MD XF

16

Кубічно , Оцінка : 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 

Спробуйте в Інтернеті!

Виявляється, все, що вам потрібно, - це умовні петлі, грань, рівна 1, і послідовна поведінка End-Of-Input.

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

Додавання / віднімання лівої грані полягає в тому, щоб цикл закінчився під час зчитування EOF.


2
Ви отримали бути жартуєш. Це неймовірно.
MD XF

О, так, це навіть має кращу оцінку, ніж моя оригінальна відповідь C #!
Каміль Дракарі

Зауважте, що завдяки оновленням мови ви можете отримати кращу оцінку, невірно зателефонувавши @- @6її можна скоротити до @всіх випадків.
MD XF

9

C # (.NET Core) , Оцінка: 129,98 11,73 10,82 9,62 10,33 10,32 10,20

-1.2 бал від пропозиції MD XF використовувати @6666...замість @6@6@6@6...повторюваного символу та переважну послідовність ініціалізації

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

Спробуйте в Інтернеті!

Моя найновіша версія насправді робить деякі маніпуляції кубом! Так!

Першим Console.Writeвгору є фіксований маніпуляційний MD XF, який створює цей куб:

   242
   202
   242
000131555313
010121535343
000131555313
   424
   454
   424

Значення цього куба полягає в тому, що одна з його сторін має суму 1, що дозволяє маніпулювати Блокнотом у меншому масштабі, ніж кратні дев'ять, і, зокрема, спрощує відносний рух, а не потрібно починати з нуля кожного символу; в цьому алгоритмі і складання, і віднімання використовуються для проходження найкоротшого шляху між символами.

Версія ініціалізації MD XF призводить до того, що сторона 2 має суму 14, що зберігає багато байтів виводу для відстаней ASCII між 14 і 20.

Тепер може обробляти входи внутрішніми новими рядками, Console.Read () отримує окремі символи до кінця файлу; див. посилання TIO, яке повинно мати вхід

Hello, 
World!

Поголив пару дробів точки, негайно вивів символ, якщо його значення ASCII просто так вже існує на стороні.

Тестовий сценарій ввічливий для MDXF


Попереднє подання тут та пояснення:

Це щось нудно, але наскільки я можу сказати, це працює. Правда, я лише спробував, Hello, World!але я запустив висновок в інтерпретаторі TIO в кубічному інтерпретаторі, і він вийшов "Привіт, світ!" тому я припустив, що це працює.

Замість того, щоб взагалі реально маніпулювати кубом, блокнот просто збільшується на суму 1 грані (9) кілька разів, поки він не отримає потрібне значення для кожного символу, а потім надрукує його.


Коментарі не для розширеного обговорення; ця розмова переміщена до чату .
Мартін Ендер

@MartinEnder Чи можете ви перемістити їх до наявної кімнати чату ?
MD XF

@MDXF Я міг, але не можу сказати, чи закінчилися вони зовсім поза місцем та контекстом у цій чаті.
Мартін Ендер

@MartinEnder Коментарі старіші за чат, тому вони просто з'являться назад у стенограмі, правда?
MD XF

Вони б. Дякую, я перенесу повідомлення.
Мартін Ендер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.