最も効率的な培養器


19

通常、コードを手動で記述するのは面倒です。あなたの課題は、ASCIIテキストをCubicallyソースコードに変換することです。

キュビック

これは、Cubicallyの簡単な概要です。リポジトリには、より完全なガイドと詳細を持っています。

Cubicallyは、私が少し前に書いた、使用するのが苦痛になるように設計されたエゾランです。2つのメモリ、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

コマンド

非整数文字はデフォルトのコマンドを設定します。デフォルトのコマンドが再度設定される前の各整数に対して、その整数でコマンドが実行されます。たとえば、5でx524y312コマンドxを実行し、2でコマンドyを実行し、4でコマンドを実行し、3でコマンドを実行し、1でコマンドを実行し、2でコマンドを実行します。

コマンドが使用する整数は、フェイスインデックスを表します。したがって、UP(0インデックス)面でx0実行xします。x1行うであろうxようにLEFT(1-インデックス付き)面上に、そして。

でコマンドを6実行すると、メモ帳の値に対してそのコマンドが実行されます。6を超える整数でコマンドを実行すると、エラーが発生します。

コマンドの例を次に示します。

  • R1 -内部の立方体が上の2番目の例のようになるように、右の面を時計回りに90°回転
  • R11 -右面を時計回りに90°に2回回します。 R2
  • +0 -UPフェイスのすべての値をメモ帳に追加します
  • +000 -UPフェイスのすべての値をメモ帳に3回追加します
  • @6 -存在しない6番目のインデックス付きの面(メモリ)を文字として印刷する
  • %4 -BACKフェースのすべての値の合計を整数として出力します

コマンドと構文の完全なリストは、リポジトリで入手できます

チャレンジ

入力として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コードを出力する必要があります。
  • テストドライバーをいじりたくない限り、プログラムは標準入力を介して入力を受け取ります。
  • プログラムは、実行時にプログラムの入力のみを生成するコードを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つの値があると考えていました。
ジョナサンアラン

回答:


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}と、メモ帳の値がになるような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

ルア、スコア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@:2/12を+551追加する「e」を印刷するには、99(9 *(5 + 5 + 1)、または9 * 11)を追加し@、出力を印刷します。入力はで読み込まれio.read()ます。

最適化には、文字間の差が9の倍数である場合の印刷後の直接加算/減算、c%9をゼロから設定するのではなく、可能であれば現在の値を除算すること、および再計算ではなく現在の値を再度印刷して文字を繰り返すことが含まれます。さらに、既に目標値を含む顔を即座に印刷するKamilの方法と:、最初は使用せず、代わりにで始まるMD XFの提案を実装しました+


1
自分の質問と回答にいつでもコメントできますが、まだ一般的なコメント権限にはまだ至っていません。このような回答を長くするべきではありません(または、より多くの人がそれを見ると、この回答だけで)
カミルドラカリ

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

Cubicallyスコア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が読み取られたときにループを終了させることです。


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 文字@6666...@6@6@6@6...、繰り返し文字の代わりに使用するMD XFの提案、および優れた初期化シーケンスから

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つが合計1であり、9の倍数よりも小さいスケールでメモ帳を操作できることです。特に、各文字をゼロから開始する必要がなく、相対移動を簡素化します。このアルゴリズムでは、加算と減算の両方を使用して、文字間の最短経路を取ります。

MD XFの初期化バージョンでは、サイド2の合計が14になり、14〜20のASCII距離で多くのバイトの出力が節約されます。

内部改行で入力を処理できるようになり、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.