가장 효율적인 배양기


19

입방체 는 코드를 수동으로 작성하기에는 너무 지루합니다. 문제는 ASCII 텍스트를 입방체 소스 코드로 변환하는 것입니다.

입방체

이것은 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

명령

정수가 아닌 문자가 기본 명령을 설정합니다. 기본 명령이 다시 한 번 설정되기 전에 각 정수에 대해 해당 정수로 명령이 수행됩니다. 예를 들어 5로 x524y312명령 x을 수행 한 다음 2로, 4로 명령을 수행 y한 다음 3으로 명령을 수행 한 다음 1로, 2로 명령을 수행 합니다.

명령이 사용하는 정수는면 인덱스를 나타냅니다. 그래서 x0수행 할 x위 (0 인덱스) 얼굴에. LEFT (1 인덱스) 얼굴에서 x1수행 x하는 등의 작업 을 수행 합니다.

with 명령을 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 초 이내에 완료해야합니다 (몇 주가 걸리는 무차별 프로그램은 없음).
  • 프로그램은 180 초 이내에 끝나는 유효한 Cubically 코드를 출력해야합니다.
  • 테스트 드라이버를 엉망으로 만들지 않는 한 프로그램은 표준 입력을 통해 입력을받습니다.
  • 프로그램은 실행시 프로그램의 입력 만 생성하는 입방체 코드를 출력해야합니다. ಠ_ಠ

채점

의사 난수 길이의 100 개의 의사 난수 문자열로 프로그램을 테스트합니다. (이 작업을 수행하는 bash 스크립트가 제공됩니다.) 다음은 점수를 매기는 방법입니다.

  • 출력 프로그램의 길이를 o로 설정하십시오 .
  • 입력 문자열의 길이를 l로 설정하십시오 .
  • 변수 ro / l 의 결과라고 하자 .
  • 모든 r 의 평균을 구합니다 : (r 1 + r 2 + r ... + r 100 ) / 100 .

이 스크립트로 테스트하십시오. 지시에 따라 수정해야합니다. 프로그램은 출력이 유효한 Cubically 코드인지 여부를 확인하지 않습니다. 스크립트가 작동하지 않으면 도와 드릴 수 있습니다. Cubically 대화방 에서 나를 핑 .



" @6존재하지 않는 6 번째 색인 얼굴 (메모장)의 합계를 문자로 인쇄"가 더 정확합니까? 인가 %4도 합? 있습니까 +명령 합 얼굴 그리고 ... 모든 값 또는 해당 추가?
Jonathan Allan

@JonathanAllan @6/ %6은 메모장 값을 문자 / 정수로 직접 인쇄합니다. @x/ %x(여기서 x는 기존 x면임 )는 인덱스 된면 에 모든 값을 추가 하고 합계를 문자 / 정수로 인쇄합니다. +지정된면의 모든 값을 레지스터에 추가합니다.
MD XF

아, 어떤 이유로 나는 메모장이 9 값을 갖는 것으로 생각했습니다.
Jonathan Allan

답변:


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이므로 Bézout의 아이덴티티에 의해 그 숫자 d의 합계 (또는 차이)에서 숫자를 구성하는 방법 이 있습니다.
  • 따라서 다음 문자가 ch있고 현재 메모장 값이 n이면 let d = ch - n, +{digits from 0 to 5}-{digits from 0 to 5}메모장 값이 되는 형식으로 Cubically 명령을 실행할 수 있습니다 ch. 그런 다음 %6메모장 값을 인쇄 하기 위해 실행하십시오 .
  • 표현할 수있는 가장 효율적인 방법 찾으려면 d얼굴 합 세트의 숫자의 합 / 차이로를, I는 0에서 128 예에 대한 모든 번호를 배낭 알고리즘을 사용하여 d=1프로그램을 얻는다 27 - 26 = 1는 인쇄, 그래서 +2-3이다, 27 - 26 = 1. input abc, 프로그램 출력으로 프로그램을 실행할 때 볼 수있는 것

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


와, 잘 했어! 배낭 알고리즘은 우리가 찾고 있던 것입니다.
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는 문자의 10 진수 값) :5+2/1를 추가 한 다음 해당면의 값을 추가하여 9로 나눌 수있는 부분을 추가합니다. 예를 들어 :2/1+551@, "e"를 인쇄하려면 :2/12를 +551더하고 99 (9 * (5 + 5 + 1) 또는 9 * 11)를 더한 @다음 출력을 인쇄합니다. 로 입력을 읽습니다 io.read().

문자 간의 차이가 9의 배수 인 경우 인쇄 후 직접 더하기 / 빼기 최적화를 통해 가능한 경우 c % 9를 처음부터 설정하는 대신 현재 값을 나누고 현재 값을 다시 계산하지 않고 다시 인쇄하여 문자를 반복합니다. 또한 이미 목표 값이 포함 된 얼굴을 즉시 인쇄하는 Kamil의 방법과 MD XF의 제안 :은 처음 에는 사용하지 말고 대신로 시작합니다 +.


1
항상 자신의 질문과 답변에 댓글을 달 수 있지만 아직 일반적인 댓글 권한이 없습니다. 이와 같은 답변으로 길지 않아야합니다 (또는 더 많은 사람들이 그것을 본다면이 답변 만 가능합니다)
Kamil Drakari

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
암시 적 얼굴 회전과 같은 최근 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

LEFT면을 더하거나 빼는 것은 EOF를 읽을 때 루프를 끝내는 것입니다.


2
당신은 가지고 농담으로. 이것은 믿기 힘든 일이야.
MD XF

아, 이건 원래 C # 답변보다 더 나은 점수를 얻었습니다!
Kamil Drakari

언어 업데이트로 인해 @암시 적으로 호출하여 더 나은 점수를 얻을 @6수 있습니다 @. 모든 경우에 단축 될 수 있습니다 .
MD XF

9

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

-1.2 문자 반복 및 우수한 초기화 시퀀스 @6666...대신 사용할 MD XF의 제안으로부터의 포인트@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의 배수보다 작은 규모로 메모장을 조작 할 수 있으며, 특히 각 문자를 0부터 시작하지 않고 상대 이동을 단순화합니다. 이 알고리즘에서 덧셈과 뺄셈은 문자 사이의 최단 경로를 취하는 데 사용됩니다.

MD XF의 초기화 버전은 측면 2의 합이 14이며 ASCII 거리 14와 20 사이의 많은 바이트 출력을 저장합니다.

이제 내부 줄 바꿈으로 입력을 처리 할 수 ​​있습니다. Console.Read ()는 파일 끝까지 개별 문자를 가져옵니다. 입력이 필요한 TIO 링크를 참조하십시오

Hello, 
World!

ASCII 값이 측면에 이미 존재하는 경우 문자를 즉시 ​​출력하여 포인트의 몇 분율을 면도했습니다.

MDXF의 테스트 스크립트 제공


여기에 이전 제출 및 설명 :

이것은 다소 지루하지만, 내가 말할 수있는 한 작동합니다. 분명히 나는 ​​단지 시도했다Hello, World! 했지만 TIO Cubically 인터프리터에서 출력을 실행했으며 "Hello, World!" 그래서 작동한다고 가정했습니다.

실제로 큐브를 실제로 조작하는 대신 메모장은 각 문자에 대해 올바른 값을 가질 때까지 1면 (9)의 합계로 반복적으로 증가한 다음 인쇄합니다.


의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
마틴 엔더

@MartinEnder 대신 기존 대화방으로 옮길 수 있습니까?
MD XF

@MDXF 나는 할 수 있었지만 그 대화방에서 완전히 벗어난 상황인지 컨텍스트를 알 수는 없습니다.
마틴 엔더

@MartinEnder 댓글이 대화방보다 오래되었으므로 대화 내용에 그대로 표시됩니다. 맞습니까?
MD XF

그들은 것입니다. 고마워, 메시지를 옮길 게
마틴 엔더
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.