Most efficient cubifier

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

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

Try it online!

Okay, I don't think I can optimize this anymore.

This version iterates through each character, adding c % 9 (where c is the character's decimal value) by doing :5+2/1, then adds the parts divisible by 9 by adding that face's value. For example: :2/1+551@ to print "e", where :2/1 adds 2, +551 adds 99 (9 * (5 + 5 + 1), or 9 * 11), and @ prints the output. Input is read with io.read().

Optimizations include directly adding/subtracting after printing if the difference between characters is a multiple of 9, dividing the current value if possible rather than setting c % 9 from scratch, and repeating characters by printing the current value again rather than recalculating it. Additionally, I've implemented Kamil's method of instantly printing any face that already contains the target value, and MD XF's suggestion to not use : at the beginning, but instead just start with a +.


Cubically, Score: 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 

Try it online!

Turns out, all you need is conditional loops, a face equal to 1, and consistent End-Of-Input behavior.

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

The adding/subtracting of the LEFT face is to get the loop to end when EOF is read.


C# (.NET Core), Score: 129.98 11.73 10.82 9.62 10.33 10.32 10.20

-1.2 point from MD XF's suggestion to use @6666... instead of @6@6@6@6... for repeating character, and superior initialization sequence

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

Try it online!

My newest version actually does some manipulation of the cube! Yay!

That first Console.Write up there is a fixed manipulation MD XF worked out that creates this cube:

   242
   202
   242
000131555313
010121535343
000131555313
   424
   454
   424

The significance of this cube is that one of its sides has a sum of 1, allowing manipulations of the Notepad on a smaller scale than multiples of nine, and in particular it simplifies relative movement rather than needing to start from zero each character; in this algorithm both addition and subtraction are used to take the shortest path between characters.

MD XF's version of the initialization causes side 2 to have a sum of 14, which saves many bytes of output for ASCII distances between 14 and 20.

Now can handle inputs with internal newlines, Console.Read() gets individual characters until End of File; see the TIO link which should have the input

Hello, 
World!

Shaved a couple fractions of a point by immediately outputting a character if its ASCII value just happens to already exist on a side.

Test Script courtesy of MDXF


Previous submission here and explanation:

This is kinda boring, but as far as I can tell it works. Admittedly I only tried Hello, World! but I ran the output in the TIO Cubically interpreter and it output "Hello, World!" so I assumed it works.

Rather than actually manipulating the cube at all, the notepad is simply incremented by the sum of the 1 face (9) repeatedly until it has the right value for each character, then prints it.