最有效的起泡器


19

Cubically过于繁琐,无法手动编写任何代码。您的挑战是将ASCII文本转换为Cubically源代码。

立体地

这只是Cubically的一个快速失败;该存储库具有更完整的指南和详细信息。

奇怪的是我前段时间写的一种esolang,使用起来很痛苦。它包含两个内存,一个3x3x3 Rubik的多维数据集和一个称为“记事本”的寄存器。

记忆

内部Rubik's Cube的初始化如下:

   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将先执行x5 指令,然后执行2指令,再执行4指令,再执行y3 指令,然后执行1指令,再执行2指令。

命令使用的整数表示面部索引。因此x0x在UP(0索引)面上执行。x1会执行x在LEFT(1索引)面上执行,依此类推。

执行任何命令6都会在记事本值上执行该命令。执行任何大于6的整数的命令将导致错误。

以下是一些示例命令:

  • R1 -将右面顺时针旋转90°,以使内部立方体看起来像上面的第二个示例
  • R11 -将右面顺时针旋转90°两次,与 R2
  • +0 -将UP面的所有值添加到记事本中
  • +000 -将UP面的所有值添加到记事本中三次
  • @6 -将不存在的第6索引面(记忆)打印为字符
  • %4 -将背面的所有值之和打印为整数

存储库中提供了命令和语法的完整列表

挑战

您将以ASCII文本作为输入,并打印一个Cubically程序作为输出。

例子(从这里这里被盗):

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秒的时间内完成(没有需要数周时间的强力程序)。
  • 您的程序必须输出有效的Cubically代码,并在180秒内完成。
  • 您的程序将通过标准输入进行输入,除非您想弄乱测试驱动程序。
  • 您的程序必须输出Cubically代码,该代码在运行时仅产生程序输入。ಠ_ಠ

计分

您将使用100个伪随机长度的伪随机字符串测试您的程序。(提供了一个bash脚本来为您完成此操作。)这是您的得分方式:

  • 令输出程序的长度为o
  • 令输入字符串的长度为l
  • 令变量ro / l的结果。
  • 求出所有r的平均值:(r 1 + r 2 + r ... + r 100)/ 100

使用此脚本进行测试。您必须按照说明进行修改。请注意,该程序不会检查输出是否有效的Cubically代码。如果您无法使脚本正常工作,我可以提供帮助。在Cubically聊天室给我ping



@6-将不存在的第6索引面(记事本)的总和打印为字符”会更准确吗?是%4还一笔?是+命令求和,然后将其添加到所有值还是...?
乔纳森·艾伦

@JonathanAllan @6/ %6只是直接将记事本值打印为字符/整数。@x/ %x(其中x是任何现有的面孔)将所有值添加到x-indexed面孔并将其总和打印为字符/整数。+将指定面上的所有值添加到寄存器。
MD XF

啊,出于某种原因,我也想到记事本也有9个值。
乔纳森·艾伦

Answers:


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生成Cubically代码)(运行Cubically代码)

说明:

  • 首先,程序打印“ RU”,这使面的总和从{0,9,18,27,36,45}{6, 15, 27, 26, 19, 42}。使面部求和集有用的原因在于gcd为1,因此根据贝索特的身份,存在一种d从这些数字的和(或差)构造任何数字的方法。
  • 因此,如果下一个字符为ch,当前记事本值为n,则让d = ch - n我们以如下形式执行Cubically命令+{digits from 0 to 5}-{digits from 0 to 5},使记事本值为ch。然后执行%6以打印记事本值。
  • 为了找到最有效的方式来表达d,如面部和组数字的和/差,我用背包算法对所有的数字从0到128。例如,为d=1的程序得到27 - 26 = 1,所以它打印+2-3,这是27 - 26 = 1。当使用输入运行程序时,可以看到abc程序输出

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


哇,干得好!我想我们正在寻找背包算法。
TehPers

请注意,由于语言的更新,通过@隐式调用可以获得更好的分数- 在所有情况下@6都可以缩短为分数@
MD XF

17

Lua,得分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/12,加+55199(9 *(5 + 5 + 1)或9 * 11),并@打印输出。用读取输入io.read()

优化包括:如果字符之间的差异是9的倍数,则在打印后直接加/减。如果可能,将当前值除以而不是从头开始设置c%9;通过再次打印当前值而不是重新计算当前值来重复字符。此外,我已经实施了Kamil的即时打印已经包含目标值的任何面的方法,以及MD XF的建议不要:在开始时使用,而只是以开头+


1
您总是可以对自己的问题和答案发表评论,但是您还没有获得一般评论特权。这样的答案不应该太长(或者更可能只有更多的人看到这个答案才有这个答案)
Kamil Drakari

2
@MDXF我不是很好:P
卡米尔·达卡里

1
您可以更改local inp = io.read()local inp = io.read("*all")。这解决了问题。
MD XF

1
另一个可能的优化-由于记事本从0开始,因此实际上不需要输出,例如:5+124,您可以只写+5124,如果正确调整,它可能会使得分降低一点。
MD XF

1
如果您更改答案以支持一些最新的Cubically更新,例如隐式转脸,您可能会获得更好的分数。
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的面和一致的输入结束行为。

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时,对LEFT面进行加/减运算可以使循环结束。


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

MD XF建议的-1.2点用于@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,允许以比9的倍数小的比例来操作记事本,尤其是它简化了相对运动,而不必每个字符都从零开始。在该算法中,加法和减法都被用来选择字符之间的最短路径。

MD XF的初始化版本使第2面的总和为14,这为14到20之间的ASCII距离节省了许多字节的输出。

现在可以使用内部换行符处理输入,Console.Read()获取单个字符,直到File End;看到应该有输入的TIO链接

Hello, 
World!

如果一个字符的ASCII值恰好已经存在于一边,则通过立即输出一个字符来剃光一点点。

测试脚本由MDXF提供


以前的提交在这里和解释:

这有点无聊,但据我所知。诚然我只是试过Hello, World!但是我在TIO Cubically解释器中运行了输出,并且输出了“ Hello,World!”。所以我认为它可行。

而不是实际操作多维数据集,只是简单地将记事本重复增加1个面(9),直到每个字符都有正确的值,然后打印出来。


评论不作进一步讨论;此对话已转移至聊天
Martin Ender

@MartinEnder您可以将它们移到现有的聊天室吗?
MD XF

@MDXF我可以,但是我无法确定它们是否最终在那个聊天室中完全不合时宜。
Martin Ender

@MartinEnder评论早于聊天室,因此它们只会出现在抄本中,对吗?
MD XF

他们将。谢谢,我将移动消息。
Martin Ender
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.