Máy lập hình hiệu quả nhất


19

Về cơ bản, quá tẻ nhạt để viết thủ công bất kỳ mã nào. Thách thức của bạn là dịch văn bản ASCII sang mã nguồn của Cuba.

Cơ bản

Đây chỉ là một sự cố nhanh chóng của Cubally; các kho lưu trữ có hướng dẫn đầy đủ hơn và chi tiết.

Thực chất là một esolang tôi đã viết cách đây một thời gian, được thiết kế để gây đau đớn khi sử dụng. Nó chứa hai mảnh bộ nhớ, khối Rubik 3x3x3 và một thanh ghi gọi là "notepad".

Ký ức

Khối Rubik nội bộ được khởi tạo như thế này:

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

Sau khi thực hiện quay 90 ° theo chiều kim đồng hồ ở mặt phải, khối bộ nhớ sẽ trông như thế này:

   002
   002
   002
111225333044
111225333044
111225333044
   554
   554
   554

Các lệnh

Một ký tự không nguyên đặt lệnh mặc định. Đối với mỗi số nguyên trước khi lệnh mặc định được đặt lại một lần nữa, lệnh được thực hiện với số nguyên đó. Ví dụ, x524y312sẽ thực hiện lệnh xvới 5, sau đó với 2, sau đó với 4, sau đó thực hiện lệnh yvới 3, sau đó với 1, sau đó với 2.

Các số nguyên mà các lệnh sử dụng đại diện cho các chỉ mục khuôn mặt. Vì thếx0 sẽ thực hiện xtrên mặt UP (0-index). x1sẽ thực hiện xtrên mặt TRÁI (1 chỉ mục), v.v.

Thực hiện bất kỳ lệnh nào 6sẽ thực hiện lệnh đó trên giá trị notepad. Thực hiện bất kỳ lệnh nào với bất kỳ số nguyên nào trên 6 sẽ dẫn đến lỗi.

Dưới đây là một số lệnh ví dụ:

  • R1 - xoay mặt PHẢI theo chiều kim đồng hồ 90 ° để khối bên trong sẽ trông giống như ví dụ thứ hai ở trên
  • R11 - xoay mặt PHẢI theo chiều kim đồng hồ 90 ° hai lần, giống hệt với R2
  • +0 - thêm tất cả các giá trị của mặt UP vào notepad
  • +000 - thêm tất cả các giá trị của mặt UP vào notepad ba lần
  • @6 - in khuôn mặt không có chỉ số thứ 6 (bộ nhớ) dưới dạng ký tự
  • %4 - in tổng của tất cả các giá trị trên mặt BACK dưới dạng số nguyên

Một danh sách đầy đủ các lệnh và cú pháp có sẵn tại kho lưu trữ .

Thử thách

Bạn sẽ lấy văn bản ASCII làm đầu vào và in chương trình Lập phương làm đầu ra.

Ví dụ (bị đánh cắp từ đâyđây ):

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

Quy tắc

  • Chương trình của bạn không được chứa từ điển chứa các bản dịch cho 100 testcase.
  • Chương trình của bạn phải hoàn thành trong vòng chưa đầy 180 giây (không có chương trình vũ phu nào phải mất hàng tuần).
  • Chương trình của bạn phải xuất mã hợp lệ hoàn thành trong vòng chưa đầy 180 giây.
  • Chương trình của bạn sẽ nhận đầu vào thông qua đầu vào tiêu chuẩn, trừ khi bạn muốn gây rối với trình điều khiển thử nghiệm.
  • Chương trình của bạn phải xuất mã Mã không tạo ra gì ngoài đầu vào của chương trình khi chạy. ಠ_ಠ

Chấm điểm

Bạn sẽ kiểm tra chương trình của mình với 100 chuỗi pseudorandom có ​​độ dài giả ngẫu nhiên. (Một tập lệnh bash được cung cấp sẽ làm điều này cho bạn.) Đây là cách bạn sẽ ghi điểm:

  • Đặt độ dài của chương trình đầu ra là o .
  • Đặt độ dài của chuỗi đầu vào là l .
  • Đặt một biến r là kết quả của o / l .
  • Tìm trung bình của tất cả r : (r 1 + r 2 + r ... + r 100 ) / 100 .

Thử nghiệm với kịch bản này. Bạn sẽ phải sửa đổi nó theo hướng dẫn. Lưu ý rằng chương trình không kiểm tra xem đầu ra có hợp lệ không. Nếu bạn không thể làm cho kịch bản hoạt động, tôi có thể giúp. Ping tôi trong phòng chat Cuba .



Liệu " @6- in tổng của khuôn mặt không có chỉ số thứ 6 (notepad) dưới dạng ký tự" có chính xác hơn không? Là %4cũng là một tổng? Là +các lệnh tổng mặt sau đó thêm nó vào tất cả các giá trị hoặc ...?
Jonathan Allan

@Jonathan ALLan @6/ %6chỉ in trực tiếp giá trị notepad dưới dạng ký tự / số nguyên. @x/ %x(trong đó x là bất kỳ mặt hiện có nào) thêm tất cả các giá trị trên xmặt -exexed và in tổng dưới dạng một ký tự / số nguyên. +thêm tất cả các giá trị trên mặt được chỉ định vào thanh ghi.
MD XF

À, vì một số lý do, tôi đã nghĩ về notepad cũng có 9 giá trị.
Jonathan Allan

Câu trả lời:


4

C ++ 11, Điểm : 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
*/

Hãy thử trực tuyến! (tạo mã khối từ ASCII)(chạy mã khối)

Giải trình:

  • Đầu tiên chương trình in "RU", làm cho tổng số mặt từ {0,9,18,27,36,45}đến {6, 15, 27, 26, 19, 42}. Điều làm cho tổng số mặt đó trở nên hữu ích là gcd là 1, do đó, theo danh tính của Bézout, có một cách để xây dựng bất kỳ số nào dtừ một tổng (hoặc chênh lệch) của các số đó.
  • Do đó, nếu char tiếp theo là chvà giá trị notepad hiện tại là vậy n, thì d = ch - nchúng ta có thể thực thi các lệnh Cubally ở dạng +{digits from 0 to 5}-{digits from 0 to 5}sao cho giá trị notepad trở thành ch. Sau đó, chỉ cần thực hiện%6 để in giá trị notepad.
  • Để tìm cách hiệu quả nhất để diễn tả dnhư một khoản / chênh lệch số liệu trong các thiết lập mặt Tóm lại, tôi sử dụng thuật toán Knapsack cho tất cả các số từ 0 đến 128. Ví dụ, cho d=1, chương trình nhận được 27 - 26 = 1, vì vậy nó in +2-3, đó là 27 - 26 = 1. Có thể thấy khi chạy chương trình với đầu vào abc, đầu ra chương trình

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


Ái chà, công việc tuyệt vời! Thuật toán Knapsack là những gì chúng tôi đang tìm kiếm tôi đoán.
TehPers

Lưu ý rằng do cập nhật ngôn ngữ, bạn có thể đạt điểm cao hơn thông qua việc gọi @ngầm - @6có thể rút ngắn @trong mọi trường hợp.
MD XF

17

Lua, Điểm : 85,91 13,50 13,20 12,70 9,41 9,32 9,83 9,66 9,12 9.06 8,03 (Trung bình)

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

Hãy thử trực tuyến!

Được rồi, tôi không nghĩ rằng tôi có thể tối ưu hóa điều này nữa.

Phiên bản này lặp lại qua từng ký tự, thêm c% 9 (trong đó c là giá trị thập phân của ký tự) bằng cách thực hiện :5+2/1, sau đó thêm các phần chia hết cho 9 bằng cách thêm giá trị của khuôn mặt đó. Ví dụ: :2/1+551@để in "e", trong đó :2/1thêm 2, +551thêm 99 (9 * (5 + 5 + 1) hoặc 9 * 11) và @in đầu ra. Đầu vào được đọc với io.read().

Tối ưu hóa bao gồm thêm / trừ trực tiếp sau khi in nếu chênh lệch giữa các ký tự là bội số của 9, chia giá trị hiện tại nếu có thể thay vì đặt c% 9 từ đầu và lặp lại các ký tự bằng cách in lại giá trị hiện tại thay vì tính toán lại. Ngoài ra, tôi đã triển khai phương pháp in ngay lập tức bất kỳ khuôn mặt nào có chứa giá trị mục tiêu của Kamil và đề xuất của MD XF không sử dụng :ngay từ đầu, mà thay vào đó chỉ bắt đầu bằng một +.


1
Bạn luôn có thể nhận xét về câu hỏi và câu trả lời của riêng bạn, nhưng bạn chưa hoàn toàn nhận được các đặc quyền nhận xét chung. Không nên dài dòng với những câu trả lời như thế này (hoặc, nhiều khả năng, chỉ là câu trả lời này một khi nhiều người khác nhìn thấy nó)
Kamil Drakari

2
@MDXF Tôi không hoàn toàn tốt như vậy: P
Kamil Drakari 26/07/17

1
Bạn có thể thay đổi local inp = io.read()thành local inp = io.read("*all"). Điều đó khắc phục vấn đề.
MD XF

1
Một tối ưu hóa có thể khác - vì notepad bắt đầu từ 0, bạn thực sự không cần phải xuất ra, ví dụ :5+124, thay vào đó bạn chỉ có thể viết +5124, điều này có thể sẽ giảm điểm một chút nếu bạn điều chỉnh đúng.
MD XF

1
Bạn có thể sẽ nhận được điểm cao hơn nếu bạn thay đổi câu trả lời của mình để hỗ trợ một số cập nhật gần đây của Cuba, chẳng hạn như quay mặt ẩn.
MD XF

16

Về cơ bản , Điểm : 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 

Hãy thử trực tuyến!

Hóa ra, tất cả những gì bạn cần là các vòng lặp có điều kiện, một mặt bằng 1 và hành vi End-Of-Input nhất quán.

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

Việc thêm / bớt mặt TRÁI là để vòng lặp kết thúc khi đọc EOF.


2
Bạn đã được đùa. Điều này thật phi thường.
MD XF

Oh hey, nó thậm chí còn có điểm cao hơn câu trả lời C # ban đầu của tôi!
Kamil Drakari

Lưu ý rằng do cập nhật ngôn ngữ, bạn có thể đạt điểm cao hơn thông qua việc gọi @ngầm - @6có thể rút ngắn @trong mọi trường hợp.
MD XF

9

C # (Lõi .NET) , Điểm: 129,98 11,73 10,82 9,62 10,33 10,32 10.20

-1,2 điểm từ đề xuất của MD XF để sử dụng @6666...thay vì @6@6@6@6...lặp lại ký tự và trình tự khởi tạo ưu việt

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

Hãy thử trực tuyến!

Phiên bản mới nhất của tôi thực sự có một số thao tác của khối lập phương! Yay!

Đầu tiên, Console.Writecó một thao tác cố định MD XF đã tạo ra khối này:

   242
   202
   242
000131555313
010121535343
000131555313
   424
   454
   424

Tầm quan trọng của khối này là một trong các cạnh của nó có tổng bằng 1, cho phép các thao tác của Notepad ở quy mô nhỏ hơn bội số của chín và đặc biệt là nó đơn giản hóa chuyển động tương đối thay vì phải bắt đầu từ 0 mỗi ký tự; trong thuật toán này cả phép cộng và phép trừ được sử dụng để đi theo con đường ngắn nhất giữa các ký tự.

Phiên bản khởi tạo của MD XF khiến cho bên 2 có tổng 14, giúp tiết kiệm nhiều byte đầu ra cho khoảng cách ASCII trong khoảng từ 14 đến 20.

Bây giờ có thể xử lý các đầu vào với dòng mới nội bộ, Console.Read () nhận các ký tự riêng lẻ cho đến khi kết thúc tệp; xem liên kết TIO cần có đầu vào

Hello, 
World!

Cạo một vài phân số của một điểm bằng cách xuất ngay một ký tự nếu giá trị ASCII của nó chỉ tồn tại ở một bên.

Kiểm tra Script lịch sự của MDXF


Gửi trước đây và giải thích:

Điều này hơi nhàm chán, nhưng theo như tôi có thể nói nó hoạt động. Phải thừa nhận rằng tôi chỉ thử Hello, World!nhưng tôi đã chạy đầu ra trong trình thông dịch TIO Cubally và nó xuất ra "Xin chào, Thế giới!" vì vậy tôi cho rằng nó hoạt động.

Thay vì thực sự thao túng khối lập phương, notepad chỉ đơn giản được tăng lên bằng tổng của 1 mặt (9) cho đến khi nó có giá trị phù hợp cho mỗi ký tự, sau đó in ra.


Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
Martin Ender

@MartinEnder Bạn có thể chuyển chúng đến phòng chat hiện tại không?
MD XF

@MDXF Tôi có thể nhưng tôi không thể biết liệu cuối cùng họ có hoàn toàn lạc lõng và bối cảnh trong phòng chat đó hay không.
Martin Ender

@MartinEnder Các bình luận cũ hơn so với phòng chat, vì vậy chúng sẽ chỉ xuất hiện trở lại trong bảng điểm, đúng không?
MD XF

Họ sẽ. Cảm ơn, tôi sẽ chuyển tin nhắn.
Martin Ender
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.