Ít nhân vật (riêng biệt) nhất cho Turing Hoàn thiện


107

Tóm lược:

Đối với bất kỳ ngôn ngữ nào, số lượng ký tự duy nhất nhỏ nhất cho ngôn ngữ của bạn là Turing-Complete là bao nhiêu?

Thử thách:

Đối với bất kỳ ngôn ngữ nào bạn chọn, hãy tìm tập hợp con nhỏ nhất của các ký tự cho phép ngôn ngữ của bạn là Turing-Complete. Bạn có thể sử dụng lại bộ ký tự của mình bao nhiêu lần tùy ý.


Ví dụ:

  • JavaScript: +!()[]( http://www.jsfuck.com )

  • Brainfuck: +<>[](giả sử kích thước ô bọc)

  • Python 2: ()+1cehrx(được làm từ các tập lệnh như exec(chr(1+1+1)+chr(1)))

Ghi điểm:

Thử thách này được tính bằng ký tự , không phải byte . Ví dụ: Điểm cho các ví dụ là 6, 5 và 9.


Ghi chú:

  • Thử thách này khác biệt với những người khác theo nghĩa bạn chỉ có ngôn ngữ của mình là Turing-Complete (không nhất thiết có thể sử dụng mọi tính năng của ngôn ngữ.)

  • Mặc dù bạn có thể, xin vui lòng không đăng câu trả lời mà không giảm các ký tự được sử dụng. Ví dụ: Brainfuck có 8 ký tự (vì mọi ký tự khác là một nhận xét theo mặc định.)

  • Bạn PHẢI cung cấp ít nhất một lời giải thích ngắn gọn về lý do tại sao tập hợp con của bạn là Turing-Complete.


90
Đơn phương , 1 ký tự. thở dài
Dennis

4
@Dennis Nó không khác với Jelly hay 05AB1E có tích hợp sẵn cho một vấn đề lý thuyết số thú vị. Thách thức này vẫn có vẻ như là một vấn đề tối ưu hóa thú vị và không tầm thường trong bất kỳ ngôn ngữ nào không được thiết kế để trở thành một tarpit.
Martin Ender

7
@MartinEnder Tôi đặc biệt thích xem câu trả lời bằng các ngôn ngữ như Java hoặc C.
Julian Lachniet

9
Vui lòng không đăng các giải pháp trong esolang trong đó giải pháp là mọi ký tự hợp lệ trong ngôn ngữ. Nó không quan tâm hay thông minh.
Pavel

20
@Pavel Không thú vị hoặc thông minh có thể có nghĩa là nó không nên được nâng cấp, nhưng chắc chắn không phải là nó không nên được đăng.
Dennis

Câu trả lời:


77

Haskell, 4 ký tự

()=;

Với ()=chúng ta có thể định nghĩa S, K và I. Các định nghĩa phải được phân tách bằng một ;hoặc một NL.

Chúng tôi xác định (==)là S (dòng thứ hai hiển thị phiên bản dễ đọc hơn):

((=====)==(======))(=======)=(=====)(=======)((======)(=======))
( a     == b      ) c       = a      c       ( b       c       )

(===) hỏi:

(=====)===(======)=(=====)
 a     === b      = a

(====) như tôi:

(====)(=====)=(=====)
(====) a     = a 

may mắn thay (==) , (===), (====), vv là tên hàm / tham số hợp lệ.

Như @ ais523 chỉ ra, SKI không đủ trong một ngôn ngữ được gõ mạnh như Haskell, vì vậy chúng tôi cần thêm một tổ hợp điểm cố định (=====):

(=====)(======)=(======)((=====)(======))
(=====) f      = f      ((=====) f      )

17
Công trình này không hoạt động trực tiếp; SKI không Turing hoàn chỉnh trong một ngôn ngữ được gõ mạnh như Haskell. Tuy nhiên, tôi tin rằng bạn có thể sử dụng kỹ thuật tương tự để xác định fix, và SKI + fix Turing hoàn tất, ngay cả trong một ngôn ngữ mạnh mẽ gõ.

Oh, vậy bạn có tiền tố những định nghĩa ở đầu mỗi chương trình?
PyRulez

@PyRulez: vâng. Theo mặc định của chúng tôi, tôi cho rằng nó đủ để có thể xây dựng các hàm với bộ ký tự đã cho - không cần phải có chương trình đầy đủ.
nimi

1
Có lẽ bạn nên thay thế (==)để nó không đụng độ với toán tử bình đẳng mặc định
tự hào

@proudhaskeller: có, nếu bạn thực sự muốn lập trình thì tốt hơn nên đổi tên (==), nhưng đoạn mã trên chỉ là một bằng chứng về sự hoàn thiện.
nimi

61

JavaScript (ES6), 5 ký tự

Cảm ơn @ETHproductions và @ATaco đã giúp đỡ việc này; đây là một dự án nhóm và mặc dù ý tưởng ban đầu là của tôi, nhiều chi tiết là của họ. Xem cuộc thảo luận trò chuyện nơi tập hợp JavaScript này được phát triển ở đây .

[]+=`

Nó được thiết lập khá tốt rằng bất kỳ chương trình Javascript nào cũng có thể được viết bằng các ký tự ( []()+!), nhưng 5 ký tự là không đủ . Tuy nhiên, đây không phải là một thách thức về việc viết JavaScript tùy ý. Đó là một thách thức về việc viết một ngôn ngữ hoàn chỉnh Turing và sử dụng thực tế là các ngôn ngữ hoàn chỉnh Turing không cần truy cập vào DOM, hoặc thậm chí I / O tương tác, hóa ra chúng ta có thể viết một chương trình với tất cả các chức năng cần thiết , thậm chí không có bất kỳ khả năng để chạy một evalhoặc tương đương.

Bootstrapping cơ bản

JavaScript rất linh hoạt với các loại. Vì vậy, ví dụ, []là một mảng trống, nhưng +[]là 0 và []+[]là chuỗi null. Đáng chú ý, việc chúng ta có thể tạo 0 với bộ ký tự này cho phép mô phỏng hiệu ứng của dấu ngoặc đơn để phân nhóm; (a)có thể được viết là [a][+[]]. Chúng ta có thể sử dụng loại mẹo này để tạo ra các nhân vật khác nhau chỉ bằng cách sử dụng +[]:

  • [][+[]]undefined(là phần tử đầu tiên của một mảng trống); vì thế
  • []+[][+[]]"undefined"(chuỗi của undefined); vì thế
  • [[]+[][+[]]]["undefined"](gói nó trong một mảng); vì thế
  • [[]+[][+[]]][+[]]"undefined"(yếu tố đầu tiên của nó); vì thế
  • [[]+[][+[]]][+[]][+[]]"u"(chữ cái đầu tiên của nó).

ulà một trong những nhân vật dễ tạo nhất, nhưng các kỹ thuật tương tự cho phép chúng ta tạo ra một loạt các nhân vật khác. Các liên kết giống như trước cung cấp cho chúng tôi danh sách sau đây của nhân vật tiếp cận với +[](đây là danh sách tương tự như đối +[](), trừ ,bởi vì đó là xây dựng chỉ có sử dụng dấu ngoặc đơn cho một mục đích nào khác hơn nhóm / ưu tiên):

0123456789acdefinotuvyIN (){}.

Chúng ta không thể đánh vần rất nhiều từ hữu ích trong bộ ký tự này (hãy nhớ rằng đây là bộ ký tự chúng ta có thể tạo thành chuỗi ; chúng ta không thể thực hiện chúng mà không cần một số loại eval). Như vậy, chúng ta cần một nhân vật khác. Chúng tôi sẽ sử dụng =, vì nó sẽ có ích sau này, nhưng hiện tại, chúng tôi sẽ sử dụng nó để đánh vần toán tử so sánh ==. Điều đó cho phép chúng tôi sản xuất falsetrue, có thể được lrsxâu chuỗi và lập chỉ mục, và ngay lập tức cho phép chúng tôi thêm vào các ký tự mà chúng tôi có thể đưa vào chuỗi.

Cho đến nay, từ quan trọng nhất mà điều này cho phép chúng ta đánh vần, mà trước đây chúng ta không thể, là constructor. Bây giờ, JavaScript có cú pháp truy cập thuộc tính trông như thế này:

object.property

nhưng bạn cũng có thể viết nó như thế này:

object["property"]

và không có gì ngăn cản chúng tôi sử dụng một thuộc tính được tính toán, thay vì một chuỗi bằng chữ. Do đó, chúng ta có thể làm một cái gì đó dọc theo dòng

object["c"+"o"+"n"+"s"+"t"+"r"+"u"+"c"+"t"+"o"+"r"]

(với các chữ cái được tạo như mô tả ở trên; mã nhanh chóng trở nên rất dài!); tương đương với object.constructor, cho phép chúng ta truy cập các hàm tạo của các đối tượng tùy ý.

Có một số thủ thuật chúng ta có thể làm với điều này. Từ trần tục đến tuyệt vời:

  • Hàm tạo của một đối tượng là một hàm. Đáng chú ý, nó có một tên và tên đó là một phần của chuỗi. Vì vậy, ví dụ, chúng ta có thể làm[[]+[]][+[]]["constructor"] để lấy tại hàm tạo cho một chuỗi, có tên là Chuỗi và sau đó xâu chuỗi nó để lấy Ský tự viết hoa. Điều này mở rộng bảng chữ cái của chúng tôi một chút và chúng tôi sẽ cần một số nhân vật mới sau này.
  • Tất cả các mảng có cùng một hàm tạo; []["constructor"] == []["constructor"]true(không giống như [] == [], đó là sai). Điều này có vẻ nhỏ, nhưng nó rất quan trọng, vì nó cho chúng ta một phương pháp lưu trữ các giá trị một cách bền bỉ; chúng ta có thể đặt một thuộc tính ngẫu nhiên trên hàm tạo và đọc lại sau. (Đây là một trong những lý do chúng tôi sử dụng =cụ thể, thay vì một trong những cách khác để tạo truefalse.) Ví dụ: chúng tôi có thể đánh giá[[]["constructor"]["a"]=[]] và sau này đọc[]["constructor"]["a"] và lấy lại cùng một mảng chúng tôi đã lưu trữ ở đó.

    Điều này đáp ứng một trong những yêu cầu chúng tôi cần cho tính đầy đủ của Turing , khả năng lưu trữ và truy xuất lượng dữ liệu tùy ý. Chúng ta có thể tạo một ô khuyết bằng cách sử dụng một mảng hai phần tử, lấy các giá trị từ bộ lưu trữ thuộc tính của hàm tạo, và sau đó lưu nó trở lại một trong các giá trị đó, cho phép chúng ta xây dựng các cấu trúc dữ liệu lớn tùy ý trong bộ nhớ; và chúng ta có thể truy cập vào bộ lưu trữ này bằng cách thực hiện ngược lại, xé nó từng mảnh cho đến khi dữ liệu chúng ta muốn có thể truy cập được. Đọc là phá hoại, nhưng điều đó có thể chấp nhận được vì chúng tôi có nhiều nơi để lưu trữ dữ liệu, vì vậy chúng tôi có thể sao chép nó khi chúng tôi đọc và sau đó đặt bản sao trở lại vị trí ban đầu.

  • Nó cho phép chúng ta lấy tại hàm tạo cho một hàm (có rất nhiều hàm chúng ta có thể truy cập với bảng chữ cái giới hạn của chúng ta; []["find"]ví dụ Array.find là dễ truy cập nhất, nhưng có nhiều hàm khác). Tại sao nó hữu ích? Chà, chúng ta thực sự có thể sử dụng nó cho mục đích dự định của một nhà xây dựng và xây dựng các hàm! Thật không may, với bộ ký tự của chúng ta, chúng ta không thể truyền cho hàm tạo Hàm một chuỗi được tính toán. Tuy nhiên, việc sử dụng `không cho phép chúng ta vượt qua nó bằng một chuỗi ký tự (ví dụ []["find"]["constructor"]`function body goes here`); điều này có nghĩa là chúng ta có thể định nghĩa các giá trị tùy chỉnh của loại hàm với bất kỳ hành vi nào khi được thực thi, miễn là chúng ta có thể diễn tả hoàn toàn hành vi đó bằng cách sử dụng []+=. Ví dụ, []["find"]["constructor"]`[]+[]`là một hàm khá nhàm chán, tính toán chuỗi null, loại bỏ nó và thoát; cái đóchức năng không hữu ích, nhưng những cái phức tạp hơn sẽ được. Lưu ý rằng mặc dù các hàm không thể lấy tham số hoặc trả về giá trị, nhưng chúng không có vấn đề gì trong thực tế vì chúng ta có thể sử dụng bộ lưu trữ thuộc tính của hàm tạo để giao tiếp từ hàm này sang hàm khác. Một hạn chế khác là chúng tôi không thể sử dụng` trong phần thân của hàm.

    Bây giờ, chúng ta có thể xác định các chức năng tùy chỉnh, nhưng điều khiến chúng ta lùi lại vào thời điểm này là khó khăn khi chúng ta gọi chúng. Ở cấp độ cao nhất của chương trình, chúng ta có thể gọi một hàm với`` , nhưng chỉ có thể gọi các hàm từ cấp cao nhất không cho phép chúng ta thực hiện bất kỳ loại vòng lặp nào. Thay vào đó, chúng ta cần các chức năng để có thể gọi cho nhau.

    Chúng tôi thực hiện điều này với một thủ thuật khá tiện lợi. Bạn có nhớ số vốn Schúng tôi tạo ra trước đó không? Điều đó cho phép chúng tôi đánh vần "toString". Chúng tôi sẽ không gọi nó; chúng ta có thể chuyển đổi mọi thứ thành chuỗi bằng cách thêm []vào chúng. Thay vào đó, chúng tôi sẽ thay thế nó. Chúng ta có thể sử dụng lưu trữ constructor để xác định các mảng liên tục dính xung quanh. Sau đó, chúng ta có thể gán các hàm đã tạo cho các toStringphương thức của mảng và các phép gán đó cũng sẽ được sử dụng. Bây giờ, tất cả những gì chúng ta phải làm là đơn giản +[]trên mảng và đột nhiên, hàm được xác định tùy chỉnh của chúng ta sẽ chạy. Điều này có nghĩa là chúng ta có thể sử dụng các ký tự+=[]để gọi các hàm và do đó các hàm của chúng ta có thể gọi nhau - hoặc chính chúng. Điều này mang lại cho chúng ta đệ quy, cho chúng ta các vòng lặp, và đột nhiên chúng ta có mọi thứ chúng ta cần cho Turing-đầy đủ.

Dưới đây là danh sách các bộ tính năng mang lại sự hoàn thiện cho Turing và cách chúng được triển khai:

  • Lưu trữ không giới hạn : các mảng lồng nhau trong lưu trữ của hàm tạo
  • Kiểm soát luồng : thực hiện bằng cách sử dụng ifvà đệ quy:
    • if: chuyển đổi một boolean thành một số và lập chỉ mục thành một mảng 2 phần tử; một phần tử chạy hàm cho thentrường hợp khi được xâu chuỗi, phần tử khác chạy hàm cho elsetrường hợp khi được xâu chuỗi
    • Đệ quy : xâu chuỗi một phần tử thích hợp của bộ lưu trữ hàm tạo
  • Lệnh trình tự : [a]+[b]+[c]đánh giá lại a, bctừ trái sang phải (ít nhất là trên các trình duyệt tôi đã kiểm tra)

Thật không may, điều này là không thực tế; Nó không chỉ quá lớn khi các chuỗi phải được xây dựng theo từng ký tự từ các nguyên tắc đầu tiên, nó cũng không có cách nào để thực hiện I / O ( không bắt buộc phải hoàn thành Turing). Tuy nhiên, nếu nó chấm dứt, ít nhất bạn có thể tìm kiếm trong bộ lưu trữ của nhà xây dựng bằng tay sau đó, vì vậy không thể gỡ lỗi các chương trình của bạn và chúng không hoàn toàn không truyền thông.


16
Nếu điều này không được đặt tên, tôi đề nghị J5h * t.
Máy

1
Một chương trình ví dụ tốt sẽ là gì? Xét nghiệm tướng? Chào thế giới?
Máy

3
Tôi, điều này thật wat ... câu trả lời ngon, giống như một bộ phim kinh dị tốt.
đã ngừng quay ngược chiều

4
Tôi nghĩ rằng toString()việc sử dụng chức năng tiêm phụ thuộc của Angular1 là cách sử dụng chức năng sáng tạo nhất. Bây giờ tôi đã thay đổi suy nghĩ của mình.
Nắng Pun

1
Dưới đây là một ví dụ: pastebin.com/QGbjmB5Y
Esolanging Fruit

55

Unary , 1 ký tự

0

Sự lựa chọn của nhân vật không thực sự quan trọng; độ dài của chương trình xác định chương trình brainfuck mà nó chuyển đến. Trong khi thông số kỹ thuật bắt buộc các 0ký tự, hầu hết các bộ chuyển đổi dường như không kiểm tra điều này.


44
Có lẽ chúng ta nên mở các vấn đề với các bộ chuyển đổi xác nhận thông số kỹ thuật, đây là một vấn đề rất nghiêm trọng.
Thuyền trưởng Man

5
Tôi sững sờ. Tôi cần 20 phút để nói liệu đó có phải là một trò đùa không.
Peter A. Schneider

3
@ PeterA.Schneider Một số googling sẽ thấy rằng ai đó thực sự thực hiện một câu hỏi theo cách này trong lý thuyết, mặc dù chuỗi kết quả là 0 có thể là con số lớn nhất tôi từng thấy trong bất kỳ bối cảnh thực tế nào và không bao giờ có thể được thực hiện trên máy thật.
Darren Ringer

12
Chuỗi số 0 đó thực sự là con số nhỏ nhất tôi từng thấy trong bất kỳ bối cảnh nào.
Matthew Đọc

1
LOL, tốt, nếu bạn làm điều gì đó ngớ ngẩn như xác định biểu tượng duy nhất của bạn là danh tính phụ gia ...: p
Darren Ringer

37

vim, 9 8 7 6 ký tự

<C-v><esc>1@ad

Chúng ta có thể xây dựng và thực hiện một chương trình vimscript tùy ý như sau:

  1. Sử dụng trình tự aa<C-v><C-v>1<esc>dd@1<esc>ddddđể có được một <C-a>đăng ký 1.

  2. Nhập chế độ chèn với a, sau đó chèn một a, sẽ được sử dụng để nhập lại chế độ chèn trong macro sau này.

  3. Đối với mỗi nhân vật trong chương trình vimscript mong muốn,

    1. sử dụng <C-v><C-v>1<esc>để chèn chuỗi literal <C-v>1,

    2. sử dụng @1( <C-a><cr>trong đó, cuối cùng <cr>là không có do nằm trên dòng cuối cùng) nhiều lần cần thiết để tăng 1giá trị cho đến khi đạt được giá trị ASCII của ký tự mong muốn,

    3. và nhập lại chế độ chèn với a.

  4. Xóa dòng (cùng với một dòng mới) vào thanh 1ghi với <esc>dd.

  5. Thực hiện kết quả dưới dạng tổ hợp phím vim bằng cách sử dụng @1, sau đó <esc>ddxóa dòng được nhập bởi dòng mới ở cuối từ bước trước.

  6. Chạy chuỗi kết quả tùy ý của byte với dd@1. Nếu nó bắt đầu bằng a :, nó sẽ được hiểu là mã vimscript và nó sẽ được chạy do dòng mới từ dd.

Tôi không tin đây là một bộ ký tự tối thiểu, nhưng nó khá dễ để chứng minh là Turing-perfect.


2
Bạn không thể làm gì i<C-v>1<ESC>để viết <C-a>và sau đó ddđể bạn có thể sử dụng @1để tăng bất kỳ số nào và dẫn đến không phải sử dụng <C-a>?
Bò lang băm

4
Wow, câu trả lời này là không thể tin được! +1!
DJMcMayhem

@KritixiLithos Điều đó cuối cùng đã hoạt động sau một chút tái cấu trúc, cảm ơn!
Doorknob

2
@ mbomb007 Trên thực tế ... do một chi tiết triển khai thú vị, hãy <C-v>10chèn một NUL thay vì \ n (đừng hỏi). Trong mọi trường hợp, yeah, nó không liên quan đến Turing-đầy đủ.
Doorknob


33

Perl, 5 ký tự

<>^es

Cũng như các ngôn ngữ script khác, ý tưởng là evalcác chuỗi tùy ý. Tuy nhiên, bộ ký tự của chúng tôi không bao gồm các trích dẫn hoặc toán tử ghép, do đó, việc xây dựng các chuỗi tùy ý sẽ phức tạp hơn. Lưu ý rằng eval^"sẽ đơn giản hơn nhiều để giải quyết, nhưng có thêm một nhân vật.

Công cụ chính của chúng tôi là s<^><CODE>ee, evals CODE, sau đó evals đầu ra của nó. Nhiều hơn ecó thể được thêm vào, với hiệu quả mong đợi.

Chúng tôi nhận được các chuỗi sử dụng <>, đó là toán tử toàn cầu trừ khi nó không hoạt động. Ký tự đầu tiên không thể là <(nếu không giống như <<toán tử), các dấu ngoặc góc cần được cân bằng và phải có ít nhất một ký tự không phải chữ cái (nếu không nó được hiểu là toán tử dòng).

Bằng cách kết hợp các chuỗi đó lại với nhau, chúng ta có thể nhận được bất kỳ tổ hợp ký tự nào ^B^V^S(*-/9;<>HJMOY[`\^begqstv, miễn là chúng ta chấp nhận có một số rác xung quanh (ba chuỗi đầu tiên là các ký tự điều khiển).

Ví dụ, giả sử chúng ta muốn có được "v99". Một cách để có được v99"><<" ^ "e>>" ^ "see" ^ "^^^", nhưng chúng ta không thể biểu diễn các chuỗi đó do các ràng buộc trên <>. Vì vậy, thay vào đó, chúng tôi sử dụng:

<^<<^>><>>^<^^^^^<>>^<^^^^^^e>^<^^^^^^^>^<^^^^^e>^<^^^^e^>^<e^^es>^<^ee^^>^<^<^^^^^>>^<^<>^^^^>^<^^^^^^^e>^<^^^^^^^^>

Các sản lượng trên Y9;v99;, khi eval-ed mang lại kết quả tương tự như một đơn vị v99(cụ thể là ký tự có mã ASCII 99).

Do đó, chúng ta có thể sử dụng toàn bộ bộ ^B^V^S(*-/9;<>HJMOY[`\^begqstvký tự để tạo chuỗi tùy ý, sau đó chuyển đổi nó như trên và gắn nó vào s<><CODE>eeeeđể thực thi nó. Thật không may, bộ ký tự này vẫn còn rất hạn chế, không có cách rõ ràng nào để thực hiện nối.

Nhưng may mắn thay, nó chứa ngôi sao. Điều này cho phép chúng ta viết *b, đánh giá chuỗi "*main::b". Sau đó, *b^<^B[MMH^V^SY>(^ B, ^ V và ^ S là các ký tự điều khiển theo nghĩa đen) cung cấp cho chúng ta (6, $&);, khi eval-ed một lần nữa, trả về giá trị của biến khớp của Perl , $&. Điều này cho phép chúng tôi sử dụng một hình thức ghép nối có giới hạn: chúng tôi có thể liên tục trả trước những thứ cần $_sử dụng s<^><THINGS>e, sau đó sử dụng s<\H*><*b^<^B[MMH^V^SY>>eeeđể đánh giá $_( \Hkhớp với mọi thứ trừ khoảng trắng ngang; chúng tôi sử dụng nó thay vì dấu chấm, không có trong bảng mã của chúng tôi).

Sử dụng 9-/, chúng ta có thể dễ dàng tạo ra tất cả các chữ số. Sử dụng các chữ số vvà ghép nối, chúng ta có thể tạo các ký tự tùy ý (vXXX mang lại ký tự có mã ASCII XXX). Và chúng ta có thể nối các chuỗi đó, vì vậy chúng ta có thể tạo các chuỗi tùy ý. Vì vậy, có vẻ như chúng ta có thể làm bất cứ điều gì.

Hãy viết một ví dụ hoàn chỉnh. Giả sử chúng ta muốn một chương trình in PID riêng của nó. Chúng tôi bắt đầu với chương trình tự nhiên:

say$$

Chúng tôi chuyển đổi nó thành ký hiệu v:

s<><v115.v97.v121.v36.v36>ee

Chúng tôi chỉ viết lại phần này bằng cách sử dụng ^B^V^S(*-/9;<>HJMOY[`\^begqstv(khoảng trắng chỉ dành cho khả năng đọc và không ảnh hưởng đến đầu ra):

s<^><
    s<^><9*9-9-9-9-9-9>e;
    s<^><v>;
    s<v\H\H><*b^<^B[MMH^V^SY>>eee;
    s<^><9*9-9-9-9-9-9>e;
    s<^><v>;
    s<v\H\H><*b^<^B[MMH^V^SY>>eee;
    s<^><99-99/-9-99/-9>e;
    s<^><v>;
    s<v\H\H\H><*b^<^B[MMH^V^SY>>eee;
    s<^><99-9/9-9/9>e;
    s<^><v>;
    s<v\H\H><*b^<^B[MMH^V^SY>>eee;
    s<^><999/9-9/-9-9/-9-9/-9-9/-9>e;
    s<^><v>;
    s<v\H\H\H><*b^<^B[MMH^V^SY>>eee;
    s<\H*><*b^<^B[MMH^V^SY>>eee;
>eee;

Cuối cùng, chúng tôi chuyển đổi chương trình trên thành chỉ <>^es: pastebin . Đáng buồn thay, điều này làm hỏng Perl với Excessively long <> operator, nhưng đó chỉ là một hạn chế kỹ thuật và không nên được tính đến.

Phew, đó là khá cuộc hành trình. Sẽ rất thú vị khi thấy ai đó nghĩ ra một bộ 5 ký tự giúp mọi thứ đơn giản hơn.

EDIT: bằng cách sử dụng một cách tiếp cận hơi khác, chúng ta có thể tránh đạt giới hạn độ dài trên <>. Trình thông dịch Brainfuck đầy đủ chức năng chỉ sử dụng <>^es: Dùng thử trực tuyến! . Tự động Perl để <>^estranspiler: pastebin .


1
Tôi hiểu rồi .. mã hóa của bạn bị thổi phồng bậc hai vì các ký tự của bạn chia thành hai nhóm, một nhóm chỉ có thể được tạo bằng cách tạo một số chẵn các ký tự cơ bản và một ký tự khác chỉ có thể được tạo bởi một số lẻ, buộc bạn phải thêm một quả cầu khác bất cứ khi nào thay đổi giữa chúng. Bất kỳ cơ hội nào bạn có thể chia chương trình thành các phần có thể đánh giá ngắn hơn gắn liền với ^hoặc các nhân vật cơ sở khác?
Ørjan Johansen

@ RjanJohansen Yep, công việc tốt phát hiện ra điều đó. Tôi đang làm việc trên một giải pháp ngay bây giờ.
Grimy

Bạn có thể làm cho ví dụ thu nhỏ đó thành một liên kết TIO Hãy thử trực tuyến!
Ørjan Johansen

7
Yêu cầu: Giải thích "cách tiếp cận hơi khác" này
CalculatorFeline

32

Python 2, 7 ký tự

exc="%\n

Bất kỳ chương trình Python 2 nào cũng có thể được mã hóa bằng 7 ký tự này ( \nlà dòng mới).

Xây dựng chuỗi tùy ý

Chúng ta có thể thực hiện nối bằng cách liên tục áp dụng toán tử thay thế %trên một chuỗi. Ví dụ, nếua=1, b=2, c=3 , "%d%%d%%%%d" % a % b % csẽ cho chúng ta chuỗi "123". May mắn thay, các chữ cái execcho chúng ta truy cập %x%cvề cơ bản là hex()chr(). Với %c, chúng ta có thể xây dựng bất kỳ chuỗi nào miễn là chúng ta có các số cần thiết đại diện cho các ký tự. Sau đó chúng ta có thể thực thi chuỗi này dưới dạng mã python bằng exectừ khóa.

Tạo số

Chúng ta có thể truy cập 01tắt ngay con dơi bằng phép so sánh ( ==). Thông qua sự kết hợp của các chữ số ghép và modulo, có thể xây dựng số 43đại diện +trong ASCII. Điều này cho phép chúng tôi xây dựng các số chúng tôi cần cho mã của chúng tôi.

Đặt nó lại với nhau

Tôi đã bỏ qua một số chi tiết trong phần giải thích này vì chúng không cần thiết trong việc hiểu làm thế nào các chương trình theo các ràng buộc này có thể được viết. Dưới đây là chương trình Python 2 tôi đã viết để chuyển đổi bất kỳ chương trình python nào thành phiên bản tương đương về chức năng chỉ sử dụng 7 ký tự này. Các kỹ thuật được sử dụng được lấy cảm hứng từ bài nộp này trên sân golf vô chính phủ của k. Một số thủ thuật đơn giản cũng được sử dụng để giữ kích thước của các chương trình được tạo trong giới hạn hợp lý.

import sys

var = {
    43: 'e',
    'prog': 'x', # the program will be stored in this variable
    'template': 'c',
    0: 'ee',
    1: 'ex',
    2: 'ec',
    4: 'xe',
    8: 'xx',
    16: 'xc',
    32: 'ce',
    64: 'cc',
    'data': 'cx', # source program will be encoded here
}

unpacker = 'exec"".join(chr(eval(c))for c in {}.split())'.format(var['data'])

source = sys.stdin.read()
charset = sorted(list(set(source+unpacker)))
codepoints = map(ord, charset)

output = (
    # create template for joining multiple characters
    '{}="%c%%c%%%%c%%%%%%%%c"\n'.format(var['template']) +

    # create 1
    '{0}={1}=={1}\n'.format(var[1], var['template']) +

    # create 0
    '{}={}==""\n'.format(var[0], var['template']) +

    # create 3
    # store it at var[43] temporarily
    (
        'exec"{0}=%x%%x"%{2}%{2}\n' +
        'exec"{0}%%%%%%%%=%x%%x%%%%x"%{1}%{2}%{1}\n'
    ).format(var[43], var[0], var[1]) +

    # create 4
    # this step overwrites the value stored at var[0]
    (
        'exec"{1}=%x%%x"%{0}%{1}\n' +
        'exec"{1}%%%%=%x%%x"%{2}%{0}\n'
    ).format(var[43], var[0], var[1]) +

    # create 43
    'exec"{0}=%x%%x"%{1}%{0}\n'.format(var[43], var[0])
)

# create powers of 2
for i in [2, 4, 8, 16, 32, 64]:
    output += 'exec"{0}={1}%c{1}"%{2}\n'.format(var[i], var[i/2], var[43])

for i, c in enumerate(codepoints):
    # skip if already aliased
    if c in var:
        continue

    # generate a new name for this variable
    var_name = ''
    if i < 27:
        for _ in range(3):
            var_name += 'exc'[i%3]
            i /= 3
    else:
        i -= 27
        for _ in range(4):
            var_name += 'exc'[i%3]
            i /= 3
    var[c] = var_name

    # decompose code point into powers of two
    rem = c
    pows = []
    while rem:
        pows.append(rem&-rem)
        rem -= rem&-rem

    # define this variable
    front = 'exec"{}={}'.format(var[c], var[pows.pop()])
    back = '"'
    for i, p in enumerate(pows):
        front += '%'*(2**i) + 'c' + var[p]
        back += '%' + var[43]
    output += front + back + '\n'

# initialise the unpacker
output += 'exec"""{}=""\n"""\n'.format(var['prog'])
i = 0
length = len(unpacker)
while i < length:
    if (length-i) % 4 == 0:
        # concat 4 characters at a time
        w, x, y, z = [var[ord(unpacker[i+j])] for j in range(4)]
        output += 'exec"{}%c={}%%{}%%{}%%{}%%{}"%{}\n'.format(var['prog'], 
                    var['template'], w, x, y, z, var[43])
        i += 4
    else:
        output += 'exec"""{}%c="%%c"%%{}"""%{}\n'.format(var['prog'],
                    var[ord(unpacker[i])], var[43])
        i += 1

# encode source data
output += var['data'] + '="""'
output += '\n'.join(var[ord(c)] for c in source)
output += '"""\n'

# execute the program
output += 'exec"exec%c{}"%{}'.format(var['prog'], var[32])

print output

Dùng thử trực tuyến


Bạn có thể thêm một số kiểm tra để xem chương trình nhập liệu đã bị giới hạn ở bộ ký tự cần thiết chưa, và nếu vậy, chỉ là con mèo.
mbomb007

26

Toán học, 5 4 ký tự

I[]

là một ký tự Unicode sử dụng riêng , hoạt động như một toán tử cho Functionphép bạn viết chữ cho các hàm không tên với các đối số được đặt tên. Nhân vật trông rất giống trong Mathicala, vì vậy tôi sẽ sử dụng câu đó cho phần còn lại của câu trả lời này cho rõ ràng.

Sử dụng này, chúng ta có thể thực hiện S, KIcombinators logic combinatory:

I -> II↦II
K -> II↦III↦II
S -> II↦III↦IIII↦II[IIII][III[IIII]]

Một vấn đề cú pháp với những vấn đề này là có độ ưu tiên rất thấp sẽ là vấn đề nếu chúng ta cố gắng truyền các đối số cho các tổ hợp này. Bạn thường sẽ khắc phục điều đó bằng cách gói một tổ hợp Ctrong ngoặc đơn như thế (C), nhưng chúng ta không có dấu ngoặc đơn. Tuy nhiên, chúng ta có thể sử dụng I[] bọc Ctrong một số phép thuật khác có độ ưu tiên đủ cao để chúng ta có thể sử dụng nó sau này:

I[C][[I[[]]I]]

Cuối cùng, để viết một ứng dụng A x y z(trong đó Alà một combinator "mở ngoặc" như trình bày ở trên, và x, y,z có thể hoặc không thể được mở ngoặc, hoặc có thể là biểu thức lớn hơn), chúng ta có thể viết:

A[x][y][z]

Điều đó đặt ra câu hỏi làm thế nào tương đương dấu ngoặc đơn thực sự hoạt động. Tôi sẽ cố gắng giải thích nó một cách đại khái theo thứ tự tôi đã đưa ra.

Vì vậy, thứ chúng ta có cú pháp để nhóm một cái gì đó là dấu ngoặc []. Chân đế xuất hiện theo hai cách trong Mathematica. Hoặc là các yêu cầu chức năng f[x], hoặc như một toán tử lập chỉ mục f[[i]](mà thực sự chỉ là tốc ký Part[f, i]). Đặc biệt, điều đó có nghĩa là cú pháp [C]không [[C]]hợp lệ. Chúng tôi cần một cái gì đó ở phía trước của nó. Đó có thể là lý thuyết. Nếu chúng ta sử dụng Ichúng ta đã có, chúng ta có thể nhận đượcI[C] ví dụ. Điều này vẫn chưa được đánh giá, bởi vì Ikhông phải là một hàm unary (nó hoàn toàn không phải là một hàm).

Nhưng bây giờ chúng ta cần một số cách để giải nén C lại, bởi vì nếu không thì nó sẽ không thực sự được đánh giá khi chúng ta cố gắng truyền một đối số xcho nó.

Đây là nơi nó có ích f[[i]]có thể được sử dụng cho các biểu thức tùy ý f, không chỉ các danh sách. Giả sử rằng fchính nó là hình thức head[val1,...,valn], sau đó f[[0]]cho head, f[[1]]cho val1, f[[-1]]cho valnvà như vậy. Vì vậy, chúng ta cần phải lấy 1hoặc -1trích xuất Clại, bởi vì I[C][[1]]hoặcI[C][[-1]] đánh giá C.

Chúng ta có thể nhận được 1từ một biểu tượng không xác định tùy ý như x, nhưng để làm điều đó, chúng ta cần một ký tự khác để phân chia ( x/xcung cấp 1cho không xác định x). Phép nhân là phép toán số học duy nhất mà chúng ta có thể thực hiện mà không cần thêm bất kỳ ký tự nào (về nguyên tắc), vì vậy chúng ta cần một số giá trị có thể được nhân lên để đưa ra -1hoặc 1. Điều này cuối cùng là lý do tại sao tôi đặc biệt chọn Icho định danh của chúng tôi. Bởi vì Ichính nó là biểu tượng tích hợp của Mathicala cho đơn vị tưởng tượng.

Nhưng điều đó để lại một vấn đề cuối cùng: làm thế nào để chúng ta thực sự tự nhân lên I? Chúng ta không thể viết IIvì nó được phân tích thành một ký hiệu duy nhất. Chúng ta cần tách các mã thông báo này mà không cần a) thay đổi giá trị của chúng và b) bằng cách sử dụng bất kỳ ký tự mới nào.

Bit cuối cùng của một phép thuật là một phần của hành vi không có giấy tờ: f[[]](hoặc tương đương Part[f]) là cú pháp hợp lệ và trả về fchính nó. Vì vậy, thay vì nhân Ivới I, chúng tôi nhân I[[]]với I. Việc chèn dấu ngoặc khiến Mathicala tìm kiếm mã thông báo mới sau đó và I[[]]Iđánh giá -1theo yêu cầu. Và đó là cách chúng tôi kết thúc với I[C][[I[[]]I]].

Lưu ý rằng chúng tôi không thể sử dụng I[]. Đây là một lời gọi vô đối của hàm I, nhưng như tôi đã nói trước đây Ikhông phải là một hàm, vì vậy điều này sẽ vẫn không được đánh giá.


Câu trả lời tuyệt vời.
Patrick Stevens

23

Python 2, 8 ký tự

exc'%~-0

Các ký tự này cho phép dịch / thực thi bất kỳ chương trình Python nào bằng chuỗi định dạng và exec. Mặc dù có thể dịch bất kỳ chương trình nào không cần thiết cho tính đầy đủ của Turing, nhưng đây là số ít ký tự nhất mà tôi biết làm cho nó trở thành TC. Điều đó thật mạnh mẽ chỉ là một phần thưởng.

Một dấu ngoặc kép cũng như bất kỳ chữ số nào ngoài số 0 cũng có thể được sử dụng. (Bây giờ tôi nghĩ về nó, 1chắc chắn sẽ tốt hơn, kết quả là các chương trình ngắn hơn, vì bạn có thể sử dụng 1, 11111, là tốt.)

Đây là chương trình print:

exec'%c%%c%%%%c%%%%%%%%c%%%%%%%%%%%%%%%%c'%-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~0%-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~0%-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~0%-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~0%-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~0

Dùng thử trực tuyến

Chương trình cơ sở yêu cầu

exec''

Mỗi nhân vật xđược thêm vào chương trình yêu cầu (char - Count):

  • % - 2**(n-1)
  • c - 1
  • - - ord(x)*2
  • ~ - ord(x)*2
  • 0 - 1

Ngoại lệ cho điều này là các tối ưu hóa / phím tắt nhất định có thể được thực hiện để làm cho chương trình được mã hóa ngắn hơn, chẳng hạn như sử dụng %'0'cho ký tự 0thay vì 48-~ , v.v.

Sử dụng thực tế (chơi golf AKA): Tôi đã sử dụng chiến thuật này để giải quyết thách thức này mà không cần sử dụng thêm một nhân vật handicap.

Tín dụng cho danh sách nhân vật và chương trình mã hóa: tại đây

Để biết thông tin về việc tìm kiếm một ràng buộc thấp hơn trên kết quả kích thước chương trình (không tối ưu hóa), xem nhận xét này .

Số lượng byte cần thiết tăng lên O(2**n), vì vậy phương pháp này không được khuyến khích để chơi gôn. Một quine sử dụng hạn chế nguồn này sẽ rất dài.


Nếu chỉ ưu tiên toán tử sẽ thực thi +hoặc -trước %, chúng ta có thể xóa một ký tự.
mbomb007

Có thể đáng chú ý là có thể dịch mọi chương trình Python sang bộ ký tự rút gọn của bạn không cần thiết cho tính đầy đủ của Turing. Mặc dù tôi tưởng tượng sẽ khó có được lượng điều khiển cần thiết mà không sử dụng exec.
Martin Ender

Đây thực sự không phải là một ngôn ngữ Turn Complete, phải không? Nó có khả năng gọi trình thông dịch cho ngôn ngữ Turn Complete, đó là trình thông dịch Python nhúng. Điều này sẽ hoạt động trong bất kỳ ngôn ngữ nào, bất kể nó có hoàn thành hay không, miễn là nó có khả năng, ví dụ, gọi một lệnh shell cho trình thông dịch khác.
mmachenry

@mmachenry Python được sử dụng riêng của nó biên dịch và thông dịch. Nó không sử dụng ngôn ngữ riêng biệt khác. Và một trình thông dịch Brainfuck đã được tạo bằng Python, vì vậy đó là Turing Complete. Sử dụng kiến ​​thức đó, lập luận của bạn là sai.
mbomb007

@ mbomb007 Không có đối số của tôi không sai. Python là một ngôn ngữ Turn Complete, rõ ràng. Việc tính toán đang được thực hiện bằng cách gọi trình thông dịch Python từ Python bằng bất kỳ ký tự nào bạn muốn cho cuộc gọi bên trong. Ngôn ngữ mà bạn chỉ định chương trình chỉ là một mã hóa, không phải là ngôn ngữ lập trình. Sử dụng điều này, thật đơn giản để tạo ra mọi ngôn ngữ lập trình Turing Complete theo nghĩa đen bằng cách sử dụng các ký tự 0 và 1 và xem các tệp nguồn dưới dạng nhị phân. Tinh thần của câu hỏi là tìm một tập hợp cú pháp của ngôn ngữ thực tế.
mmachenry

23

C (không thể truy cập), 24 18 13 ký tự

aimn[]={};,1+

Điều này bao gồm tất cả các chương trình của mẫu

main[]={<sequence of constants>};

... Trong đó chuỗi các hằng số (có dạng 1 + 1 + 1 ...) chứa biểu diễn mã máy của chương trình của bạn. Điều này giả định rằng môi trường của bạn cho phép tất cả các phân đoạn bộ nhớ được thực thi (dường như đúng với tcc [cảm ơn @Dennis!] Và một số máy không có bit NX). Mặt khác, đối với Linux và OSX, bạn có thể phải thêm từ khóa constvà đối với Windows, bạn có thể phải thêm#pragma dấu hiệu rõ ràng vào phân đoạn là có thể thực thi được.

Ví dụ, chương trình sau được viết theo kiểu trên in Hello, World!trên Linux và OSX trên x86 và x86_64.

main[]={111111111+111111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+11111+11111+11111+11111+11111+11111+11111+11111+111+11+11+11+11+11+11+1+1,1111111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+1111111+1111111+111111+11111+11111+11111+11111+11111+11111+1111+1111+1111+111+111+111+111+111+111,1111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+111111+111111+111111+111111+11111+11111+11111+1111+1111+1111+1111+1111+1111+1111+1111+111+111+111+111+111+111+111+111+111+11+11+11+11+11+1+1+1+1+1+1+1,1111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+1111+1111+111+111+111+111+111+111+111+11+11+11+11+11+11+1+1+1+1,111111111+111111111+111111111+111111111+111111111+1111111+1111111+1111111+1111111+111111+111111+1111+1111+1111+1111+1111+1111+111+111+111+111+111+11+11+11+11+1+1+1+1,111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+111111+111111+111111+1111+1111+1111+111+111+111+111+111+11+11+11+11+11+11+1+1+1+1+1+1,111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+111+111+111+111+111+111+11+11+11+11+11+11+11+1,1111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+111111+111111+111111+111111+111111+111111+111111+111111+11111+11111+11111+11111+11111+1111+1111+1111+1111+1111+1+1+1+1+1,1111111111+111111111+111111111+111111111+111111111+111111111+111111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+11111+11111+11111+11111+1111+1111+111+111+111+111+111+111+111+111+111+11+11+11+11+11+1+1+1+1+1+1+1+1+1,1111111111+1111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+111111+111111+111111+111111+11111+11111+1111+1111+1111+1111+1111+1111+1111+111+111+111+111+111+11+11+1+1+1+1+1,1111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+111111+111111+111111+111111+11111+11111+11111+11111+1111+1111+1111+1111+1111+111+11+1+1+1+1+1,1111111111+1111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+11111+111+111+111+111+1+1+1+1+1+1+1,1111111111+1111111111+1111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+11111+11111+1111+1111+111+111+111+111+111+111+111+111+111+11+11+11+11+11+11+1+1+1,1111111111+111111111+111111111+111111111+1111111+1111111+1111111+111111+111111+111111+111111+111111+111111+111111+1111+1111+1111+1111+1111+1111+1111+1111+111+111+111+111+111+111+111+111+111+1+1+1+1+1+1,111111+111111+11111+11111+11111+11111+11111+11111+11111+1111+1111+1111+1111+1111+1111+1111+1111+111+111+111+11+11+11+11+11+11+11+11+11+11,11111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+1111+1111+111+111+111+111+111+111+11+11+11+11+11+11+11+1+1+1,111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+1111+1111+111+111+111+11+11+11+1,111111111+111111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+11111+1111+1111+111+11+11+1+1+1+1+1,11111+11111+11111+11111+1111+1111+1111+1111+111+111+111+111+111+111+111+111+111+11+11+11+1+1+1+1+1};

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


2
@GB: Zero khá dễ tránh sử dụng ít nhất mã máy x86 (đây không phải là hướng dẫn cực kỳ quan trọng), đặc biệt là vì sự cố chỉ xảy ra nếu bạn có bốn byte không liên tiếp.

2
@GB Trên một máy với ints chút 320==1111111111+1111111111+1111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+111+111+111+111+111+11+11+11+11+11+11+11+1
ceilingcat

3
tcc cho phép bạn đi mà không cần const. tio.run/nexus/ Kẻ
Dennis

8
@GB Tôi mới nhận ra một đại diện ngắn hơn là 01==11
trần nhà

3
@ wizzwizz4, nó không hoàn toàn là C trong mọi trường hợp, không phải trong bất kỳ ý nghĩa nào làm cho nó Turing hoàn chỉnh. Nó không có ngữ nghĩa C gì cả. Vì dù sao bạn cũng dựa vào các chi tiết về trình biên dịch và môi trường thực thi để có được bất cứ thứ gì có thể chạy được, bạn cũng có thể cho phép một điểm nhập được đặt tên tùy ý.
John Bollinger

20

Võng mạc , 6 ký tự

$%`{¶

Cũng như các nguồn cấp dữ liệu (0x0A).

Một mặt tôi ngạc nhiên rằng tôi có thể đạt được mức thấp này. Mặt khác, tôi rất không hài lòng với việc đưa vào . Mỗi cái $`{được sử dụng lại cho hai hoặc thậm chí ba mục đích, nhưng cùng nhau chỉ phục vụ một mục đích. Điều đó làm cho chúng có vẻ khá lãng phí và phá hủy một chút sự thanh lịch của phương pháp này. Tôi hy vọng rằng có một cách để đánh bại công trình này.

Trên để chứng minh. Tôi sẽ mô tả một cách đơn giản để dịch các hệ thống thẻ tuần hoàn sang Retina bằng các ký tự trên.

Trước hết, chúng tôi sẽ sử dụng `{cho bảng chữ cái nhị phân thay vì 01. Điều này là thuận tiện, bởi vì chúng không cần phải được thoát trong một regex, nhưng chúng có ý nghĩa cho Retina hoặc theo cú pháp thay thế. Tôi đang sử dụng `cho 0{cho 1, nhưng sự lựa chọn này là tùy ý. Hơn nữa, chúng tôi sẽ đảo ngược chuỗi (và sản phẩm) trong bộ nhớ, bởi vì làm việc với ký tự cuối cùng cho phép chúng tôi sử dụng $$`thay vì ^$' tối đa hóa việc tái sử dụng ký tự.

Nếu từ ban đầu được biểu thị bởi Sisản xuất (đảo ngược) được gọi , chương trình kết quả sẽ như sau:pi


S
{`

{$
¶p1$%``
``$

{$
¶p2$%``
``$

{$
¶p3$%``
``$

...

Cấu trúc này chắc chắn phát triển trong bộ nhớ mỗi khi sản xuất được áp dụng và không có khả năng chấm dứt - thực tế, tại thời điểm mà hệ thống thẻ tuần hoàn sẽ chấm dứt (khi chuỗi làm việc trở nên trống rỗng), hành vi của chương trình Retina kết quả sẽ trở thành về cơ bản không xác định.

Hãy xem những gì chương trình làm:


S

Chúng tôi bắt đầu bằng cách khởi tạo chuỗi làm việc với từ ban đầu.

{`

Điều này bao bọc phần còn lại của chương trình chạy cho đến khi nó không thay đổi chuỗi kết quả (hey, phát hiện vòng lặp vô hạn tích hợp ngây thơ miễn phí ...). Hai linefeed ở đó không thực sự cần thiết, nhưng chúng tách vòng lặp rõ ràng hơn khỏi các sản phẩm riêng lẻ. Phần còn lại của chương trình trải qua từng sản phẩm, và do vòng lặp, chúng tôi xử lý chúng một cách hiệu quả theo chu kỳ nhiều lần.

Mỗi sản xuất được xử lý bởi hai giai đoạn. Đầu tiên chúng ta xử lý trường hợp biểu tượng hàng đầu (hoặc trong trường hợp của chúng ta) {, trong trường hợp đó chúng ta sử dụng sản xuất:

{$
¶pi$%``

Regex chỉ khớp nếu chuỗi kết thúc {. Nếu đó là trường hợp, chúng tôi thay thế nó bằng:

  • Một dòng cho ăn ( ). Chúng ta sẽ chỉ làm việc với dòng cuối cùng của chuỗi làm việc, vì vậy điều này loại bỏ hiệu quả chuỗi hoạt động cho đến nay (đó là lý do tại sao việc sử dụng bộ nhớ của chương trình sẽ tăng lên và phát triển).
  • Sản phẩm hiện tại ( ) mà chúng tôi đang chuẩn bị cho chuỗi hoạt động (nơi hệ thống thẻ tuần hoàn nối thêm nó).pi
  • Chuỗi làm việc còn lại trước đó ( $%`). Đây là lý do tại sao chúng ta cần chèn : $%`chọn mọi thứ còn lại của trận đấu, nhưng chỉ trên cùng một dòng. Do đó, điều này không thấy tất cả những thứ linh tinh chúng tôi để lại từ các sản phẩm trước đó. Thủ thuật này cho phép chúng ta khớp một cái gì đó ở cuối chuỗi làm việc để chèn một cái gì đó vào đầu chuỗi làm việc, mà không phải sử dụng cái gì đó như (.+)$1 sẽ làm nổ đáng kể số lượng ký tự chúng ta cần.
  • Một backtick duy nhất ( `). Điều này thay thế một cách hiệu quả {( 1-symbol) mà chúng ta đã khớp với `(0 -symbol) để giai đoạn tiếp theo không cần biết liệu chúng ta đã xử lý sản xuất hiện tại hay chưa.

Phần thứ hai của mỗi sản xuất sau đó là trường hợp tầm thường trong đó sản xuất bị bỏ qua:

``$

Chúng tôi chỉ đơn giản là xóa một dấu vết `. Lý do chúng ta cần hai `trên dòng đầu tiên là Retina coi backtick đầu tiên là sự phân chia giữa cấu hình và regex. Điều này chỉ đơn giản là cung cấp cho nó một cấu hình trống để chúng ta có thể sử dụng backticks trong chính regex.


20

Java 7, 18 17 ký tự

\bcdefu0123456789

Tất cả các mã nguồn java có thể được giảm xuống các điểm mã unicode. "a" là không cần thiết vì nó chỉ được sử dụng cho*:jJzZ . Dấu hoa thị được sử dụng để nhân hoặc chặn bình luận. Phép nhân chỉ là phép cộng lặp lại và bạn có thể sử dụng các nhận xét dòng đơn thay thế (hoặc chỉ bỏ qua chúng). Dấu hai chấm được sử dụng cho các toán tử ternary, mà bạn có thể sử dụng một câu lệnh if để thay thế và các vòng lặp foreach, có thể được thay thế bằng các vòng lặp thông thường cho các vòng lặp. j và z không phải là một phần của bất kỳ từ khóa nào trong java.

Cố gắng loại bỏ bất kỳ ký tự nào khác yêu cầu chúng tôi thêm ít nhất một trong các ký tự được yêu cầu trong tấm nồi hơi Java class a{public static void main(String[]a){}}. Xem bên dưới:

1 -> a (which has already been removed)
2 -> r (required for "String")
3 -> S (required for "String")
4 -> t (required for "static")
5 -> S (required for "String")
6 -> v (required for "void")
7 -> g (required for "String")
8 -> ( (required for "main(String[]a)"
9 -> i (required for "static")
b -> { (required for "class a{")
c -> l (required for "class")
d -> } (required for "(String[]a){}}")
e -> n (required for "main")
f -> o (required for "void")

Dưới đây là một ví dụ với chương trình Hello World Hãy thử trực tuyến!

Java 8, 16 ký tự

\bdefu0123456789

Cảm ơn ais523 đã chỉ ra điều này. Java 8 cho phép các giao diện có các phương thức tĩnh, điều đó có nghĩa là chúng ta có thể bỏ "c" vì chúng ta không cần nó cho "l" trong "class". "c" được sử dụng để ,<lL\|cuối cùng chúng tôi mất chức năng java nhiều hơn một chút so với khi chúng tôi xóa "a" nhưng chúng tôi vẫn có đủ để hoàn thành. Hãy thử trực tuyến!


3
Chắc chắn, việc tìm ra những chữ số thập lục phân nào có thể được bỏ qua là phần thú vị để giải quyết điều này trong Java? :)
Martin Ender

@MartinEnder hoàn toàn. Tôi dự định làm việc này nhiều hơn khi tôi có chút thời gian
Chọc

6
Và tôi, người đã sẵn sàng viết một cái gì đó Java, 127 characters... Nice one, Poke;)
Olivier Grégoire

Dựa trên các ký tự được yêu cầu trong câu trả lời của tôi , tôi không tin bất kỳ chữ số hex nào khác có thể bị xóa.

3
Nếu bạn chuyển sang Java 8, bạn có thể làm điều đó trong 16; Java 8 cho phép các giao diện có các phương thức tĩnh, cho phép bạn thả c(tất cả các chữ cái interfacevẫn có thể truy cập được mà không có ahoặc cbằng chữ hex của bạn).

19

Mê cung , 5 ký tự

~{}

Cộng với nguồn cấp dữ liệu (0x0A) và dấu cách (0x20).

Tôi sẽ phác thảo một bằng chứng dưới dạng rút gọn từ Smallfuck (một biến thể Brainfuck rút gọn sử dụng các ô 1 bit). Lưu ý rằng bản thân Smallfuck không phải là Turing-Complete vì ngôn ngữ chỉ định rằng băng của nó phải là hữu hạn, nhưng chúng ta sẽ giả sử một biến thể của Smallfuck với một băng vô hạn, sau đó sẽ là Turing-Complete (vì Labyrinth không có bộ nhớ hạn chế theo thiết kế).

Một bất biến quan trọng trong suốt quá trình giảm này sẽ là mọi chương trình (hoặc chương trình con) sẽ dẫn đến chương trình Labyrinth (hoặc chương trình con) bắt đầu và kết thúc trên cùng một hàng và kéo dài một số cột chẵn.

Labyrinth có hai ngăn xếp ban đầu chứa đầy một lượng vô hạn (ẩn) 0. {}thay đổi giá trị hàng đầu giữa các ngăn xếp này. Nếu chúng ta coi đỉnh của ngăn xếp chính là "ô" hiện tại, thì hai ngăn xếp này có thể được xem là hai nửa bán vô hạn của băng vô hạn được sử dụng bởi Smallfuck. Tuy nhiên, sẽ thuận tiện hơn khi có hai bản sao của mỗi giá trị băng trên ngăn xếp, để đảm bảo bất biến được đề cập ở trên. Do đó <>sẽ được dịch sang {{}}, tương ứng (bạn có thể trao đổi chúng nếu bạn muốn).

Thay vì cho phép các giá trị ô 01, chúng tôi đang sử dụng 0-1, chúng tôi có thể chuyển đổi giữa với ~(phủ định bitwise). Các giá trị chính xác không quan trọng đối với các mục đích của Turing-đầy đủ. Chúng ta phải thay đổi cả hai bản sao của giá trị trên ngăn xếp, điều này mang lại cho chúng ta bản dịch có độ dài đồng đều: *trở thành ~}~{.

Điều đó để lại các lệnh điều khiển luồng []. Labyrinth không có luồng điều khiển rõ ràng, mà thay vào đó, luồng điều khiển được xác định bởi cách bố trí mã. Chúng tôi yêu cầu không gian và nguồn cấp dữ liệu để thực hiện bố trí đó.

Đầu tiên, lưu ý rằng đó ~~là không có, vì cả hai ~hủy bỏ hiệu quả. Chúng ta có thể sử dụng điều này để có các đường dẫn dài tùy ý trong mã, miễn là độ dài của chúng là chẵn. Bây giờ chúng ta có thể sử dụng cấu trúc sau để dịch AA[BB]CCsang Labyrinth (Tôi đang sử dụng các chữ cái kép để kích thước của mỗi đoạn trong Labyrinth là chẵn, như được đảm bảo bởi bất biến):

      ~~~~
      ~  ~~~
AA~~..~~~~ ~CC
   ~     ~
   ~     ~
   ~     ~
   ~~~BB~~

Ở đây, ..là một số phù hợp trong ~đó phù hợp với chiều rộng của BB.

Một lần nữa, lưu ý rằng chiều rộng của xây dựng vẫn còn.

Bây giờ chúng ta có thể đi qua cách vòng lặp này hoạt động. Mã được nhập thông qua AA. Việc đầu tiên ~~không làm gì và cho phép chúng tôi đến ngã ba. Điều này gần tương ứng với [:

  • Nếu giá trị ô hiện tại bằng 0, IP sẽ tiếp tục đi thẳng, cuối cùng sẽ bỏ qua BB. Phần ..vẫn là một no-op. Sau đó, chúng tôi đạt được một ~tại một ngã ba khác. Bây giờ chúng ta biết rằng giá trị hiện tại là khác không, vì vậy IP sẽ quay đầu về hướng bắc. Nó đi vòng quanh khúc quanh ở đỉnh, cho đến khi đến ngã ba khác sau sáu giờ ~. Vì vậy, tại thời điểm đó, giá trị hiện tại vẫn khác không và IP quay đầu lại để di chuyển về phía đông CC. Lưu ý rằng ba ~trước khi CCtrả về giá trị hiện tại 0, như là khi vòng lặp bị bỏ qua.
  • Nếu giá trị ô hiện tại ở đầu vòng lặp khác không, IP sẽ quay về hướng nam. Nó chạy thêm sáu lần nữa ~trước khi đến BB(không làm gì), và sáu lần nữa ~trước khi đến ngã ba tiếp theo. Điều này gần tương ứng với ].
    • Nếu ô hiện tại bằng không, IP sẽ tiếp tục di chuyển về phía bắc. Cái tiếp theo ~làm cho giá trị khác không, do đó IP có đường nối thứ hai này, nó hợp nhất đường dẫn với trường hợp vòng lặp bị bỏ qua hoàn toàn. Một lần nữa, ba ~trả giá trị về 0 trước khi đạt CC.
    • Nếu ô hiện tại khác không, IP sẽ quay về hướng tây. Có ~trước ngã ba tiếp theo, điều đó có nghĩa là tại thời điểm này giá trị hiện tại bằng 0 để IP tiếp tục đi về phía tây. Sau đó, sẽ có một số lẻ ~trước khi IP đạt đến điểm nối ban đầu một lần nữa, để giá trị được trả về -1và IP di chuyển về phía nam vào lần lặp tiếp theo.

Nếu chương trình chứa bất kỳ vòng lặp nào, thì đầu tiên AAcần phải được mở rộng đến đầu chương trình để IP tìm đúng ô để bắt đầu:

~     ~~~~
~     ~  ~~~
AA~~..~~~~ ~CC
   ~     ~
   ~     ~
   ~     ~
   ~~~BB~~

Đó là điều đó. Lưu ý rằng các chương trình do việc giảm này sẽ không bao giờ chấm dứt, nhưng đó không phải là một phần của các yêu cầu về tính đầy đủ của Turing (xem xét Quy tắc 101 hoặc Fractran).

Cuối cùng, chúng tôi còn lại với câu hỏi liệu điều này là tối ưu. Về các ký tự khối lượng công việc, tôi nghi ngờ rằng có thể làm tốt hơn ba lệnh. Tôi có thể thấy một cấu trúc thay thế dựa trên các máy Minsky có hai thanh ghi, nhưng điều đó sẽ yêu cầu =()hoặc =-~, chỉ có một lệnh thao tác ngăn xếp nhưng sau đó là hai lệnh số học. Tôi rất vui khi được chứng minh là sai về điều này. :)

Đối với các lệnh bố trí, tôi tin rằng các nguồn cấp dữ liệu là cần thiết, bởi vì luồng điều khiển hữu ích là không thể trên một dòng. Tuy nhiên, không gian không cần thiết về mặt kỹ thuật. Về lý thuyết, có thể đưa ra một công trình lấp đầy toàn bộ lưới bằng ~{}(hoặc =()hoặc =-~) hoặc sử dụng bố cục rách rưới trong đó các đường không có cùng chiều dài. Tuy nhiên, viết mã như thế là vô cùng khó khăn, vì Labyrinth sau đó sẽ coi mỗi ô là một điểm nối và bạn cần thực sự cẩn thận để giữ cho mã không bị phân nhánh khi bạn không muốn. Nếu bất cứ ai có thể chứng minh hoặc bác bỏ việc bỏ qua khoảng trống có thể cho tính đầy đủ của Turing hay không, tôi sẽ vui lòng đưa ra một khoản tiền thưởng lớn cho điều đó. :)


19

Haskell, 5 7 ký tự

()\->=;

Là một ngôn ngữ chức năng, Haskell tất nhiên có lambdas, vì vậy việc mô phỏng phép tính lambda rất dễ dàng. Cú pháp cho lambdas là vì vậy chúng tôi cần ít nhất là các ký tự . Ngoài ra, chúng ta cần một số lượng ký hiệu biến không giới hạn để có thể xây dựng các biểu thức lambda tùy ý. May mắn chúng ta không cần bất kỳ nhân vật mới cho điều này, bởi vì , , , ..., là tất cả các tên biến hợp lệ. Trong thực tế, mọi sự kết hợp của dấu ngoặc đơn bên trong là một tên biến hợp lệ, ngoại trừ chỉ và , được dành riêng cho các biểu thức lambda, và , bắt đầu một nhận xét dòng.(\variable->body)argument()\->
(>)(>>)(>>>)\->\->--

Ví dụ:

  • S = (\(>)(\\)(-)->(>)(-)((\\)(-)))loại để(t2 -> t -> t1) -> (t2 -> t) -> t2 -> t1
  • K = (\(>)(-)->(>))loại đểt -> t1 -> t
  • Tôi = (\(>)->(>))loại đểt -> t

Chỉnh sửa: Tuy nhiên, như ais523 đã chỉ ra trong các nhận xét, công trình này thực hiện việc tính toán lambda , bản thân nó không phải là Turing- perfect vì nó không có khả năng nhập các vòng lặp vô hạn. Để khắc phục điều này, chúng ta cần một số chức năng thực hiện đệ quy. Cho đến nay chúng tôi đã sử dụng lambdas không tên, không thể tự gọi mình, bởi vì, tốt, họ không có tên. Vì vậy, chúng ta phải thêm các ký tự =;để thực hiện một fixchức năng:

(>)=(\(-)->(-)((>)(-)));   -- equivalent to: f =(\ x -> x ( f  x ));

Với tuyên bố này, tính toán lambda của chúng tôi đã hoàn tất Turing, tuy nhiên đã thêm =;, chúng tôi không cần lambdas nữa, như bạn có thể thấy trong câu trả lời của nimi chỉ sử dụng ()=;.


Về mặt kỹ thuật, nó có bị xóa trong thời gian biên dịch không main?
PyRulez

4
Công cụ tính toán kết hợp SKI được gõ đơn giản không phải là Turing-Complete; bạn cần một phép tính lambda chưa được đánh dấu cho điều đó. Thật không may, như các cuộc biểu tình của bạn đề cập, Haskell đặt một cách hiểu được gõ vào mã theo mặc định.

@PyRulez Theo quy tắc mặc định, tôi cho rằng các chức năng được chấp nhận.
Laikoni

@ ais523 Các tổ hợp SKI chỉ là một ví dụ, sử dụng các thuật ngữ lambda tùy ý có thể được xây dựng, ví dụ như số nhà thờ và các chức năng trên chúng.
Laikoni

@ ais523 có bao nhiêu tổ hợp đã gõ Lambda Tính cần phải hoàn thành? Tôi nghĩ rằng bạn chỉ cần kết hợp y, phải không?
PyRulez

18

CJam, 3 nhân vật

Đã xóa )theo đề xuất của Martin Ender

'(~

Tương tự như Python được đưa ra làm ví dụ.

Sử dụng '~bạn có thể có được ~nhân vật. Sau đó, bằng cách sử dụng (, bạn có thể giảm nó để lấy bất kỳ ký tự nào bạn muốn ( ~là ký tự ASCII có thể in cuối cùng). ~evals bất kỳ chuỗi như mã CJam bình thường. Các chuỗi có thể được xây dựng bằng cách lấy ký tự [(thông qua giảm dần ~), đánh giá nó, đặt một số chuỗi các ký tự khác, sau đó đánh giá ký tự ]. Thông qua đó, bạn có thể xây dựng và thực hiện bất kỳ chương trình CJam nào chỉ bằng ba ký tự này.

Chỉ tính 2 + 2 '(~


đối với một thử thách khác, ai đó đã tạo một chương trình lấy bất kỳ chương trình cjam nào và tự động biên dịch nó thành tập hợp con này. Tôi ước tôi có thể tìm thấy nó
Zwei

1
Tôi đã quản lý để chơi golf xuống chương trình 2 + 2 một cách đáng kể '~((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((~'~(((((((((((((((((((((((((((((((~'~(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((~
Zwei

@Zwei thật tuyệt, phù hợp với tên của bạn
Chromium

18

Brain-Flak , 6 nhân vật

(){}[]

Brain-Flak là một ngôn ngữ tối giản chỉ có 8 ký tự có sẵn. Tuy nhiên, có thể chứng minh rằng tồn tại một tập hợp con Brain-Flak cũng hoàn thành Turing chỉ với 6 ký tự.

Điều đầu tiên chúng ta sẽ làm là triển khai một Máy Minsky chỉ với một chồng Brain-Flak. Nếu chúng ta có thể chứng minh rằng một máy Minsky là có thể với chỉ có một ngăn xếp chúng ta có thể chứng minh rằng não-Flak là Turing trọn vẹn nếu thiếu sự <>[]nilads. Điều này sẽ không lưu bất kỳ nhân vật nào ngay lập tức nhưng sẽ trong tương lai khi chúng tôi cho thấy điều đó <...>là không cần thiết.

Máy Minsky là một loại máy tự động hoàn chỉnh Turing có số lượng đăng ký không giới hạn và hai thanh ghi:

  • Tăng đăng ký

  • Nếu giảm khác không chuyển sang một lệnh được chỉ định

Để thiết lập cấu trúc goto trong Brain-Flak, chúng ta có thể sử dụng đoạn mã sau:

(({}[()])[(())]()){(([({}{})]{}))}{}{(([({}{}(%s))]{}))}{}

Điều này sẽ làm giảm bộ đếm và chạy %snếu không. Một loạt các chuỗi này được nối với nhau sẽ cho phép chúng ta đặt một số trên ngăn xếp sẽ cho biết dòng nào chúng ta muốn goto. Mỗi trong số này sẽ làm giảm đỉnh của ngăn xếp nhưng chỉ một trong số chúng thực sự sẽ chạy mã.

Chúng tôi sử dụng điều này như một trình bao bọc cho tất cả các hướng dẫn Máy Minsky của chúng tôi.

Tăng một thanh ghi cụ thể là khá dễ dàng mà không cần chuyển đổi ngăn xếp. Nó có thể đạt được với công thức chuỗi này:

"({}<"*n+"({}())"+">)"*n

Ví dụ để tăng đăng ký thứ 3, chúng tôi sẽ viết đoạn mã sau:

({}<({}<({}<({}())>)>)>)

Bây giờ chúng ta chỉ cần thực hiện thao tác thứ hai. Kiểm tra nếu một số bằng 0 là khá đơn giản trong Brain-Flak:

(({})){(<{}%s>)}{}

sẽ chỉ thực hiện %snếu ĐKDV bằng không. Vì vậy, chúng tôi có thể thực hiện hoạt động thứ hai của chúng tôi.

Vì Minsky Machines đang hoàn thành Brain-Flak cũng hoàn thành Turing mà không cần sử dụng <>[]vận hành.

Tuy nhiên, chúng tôi chưa giảm số lượng ký tự vì <...>[...]vẫn đang được sử dụng. Điều này có thể được khắc phục với sự thay thế đơn giản. Vì <...>thực sự tương đương với [(...)]{}trong mọi trường hợp. Do đó, Brain-Flak hoàn thành Turing mà không cần sử dụng các ký tự <>ký tự (cộng với tất cả các no-op).


"bởi vì <...>[...]vẫn đang được sử dụng." Tuy nhiên, bạn đã không loại bỏ [...]. Hãy sửa chữa.
Máy

Câu hỏi: Có [...]thực sự cần thiết? Đẩy 0 có thể được thực hiện khi bắt đầu với ({})(nhưng nó phụ thuộc vào một ngăn xếp trống, vì vậy 0 sẽ phải được xáo trộn cẩn thận) Vấn đề chính là có thể đi xuống ngăn xếp mà không có quyền truy cập <...>(không thể mô phỏng được nữa)
Máy

16

> <> , 3 ký tự

> <> có thể thực hiện trong 3 với 1p-, trong đó:

1          Push 1
p          Pop y, x, c and put the char c in cell (x, y) of the codebox
-          Subtraction: pop y, x and push x-y

pcung cấp sự phản chiếu, sửa đổi mã nguồn 2D bằng cách đặt ký tự vào bảng mã. Với 1-, bạn có thể đẩy bất kỳ số nào lên ngăn xếp kể từ khi 1-trừ đi một và 111-1--( x-(1-1-1) = x+1) thêm một số.

Khi tất cả các 1p-lệnh đã được thực thi, con trỏ lệnh bao bọc xung quanh, cho phép nó thực thi mã "thực".

Một chương trình ví dụ tính toán các số Fibonacci (từ câu trả lời này ) là:

111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--11-11-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1--11-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1--11-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1--11-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1--11-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--11-1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--11p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1-1-1-1-1-1--1p

Hãy thử trực tuyến! Khi tất cả các 1p-lệnh đã được thực thi, codebox trông như thế này:

01aa+v1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1- ...
@+&1->:?!;&:nao:

Chặn mọi thứ sau vdòng đầu tiên, đây là chương trình Fibonacci> <> tiêu chuẩn.


13

bash, 9 ký tự

01456\$ '

Bash có một cú pháp $'\nnn'để nhập các ký tự có giá trị bát phân ascii của chúng. Chúng ta có thể nhập evallệnh theo định dạng này là $'\145\166\141\154'. Đầu tiên chúng ta biến kết quả mong muốn thành giá trị bát phân của nó. Sau đó, chúng tôi chuyển đổi bất kỳ giá trị bát phân nào bằng các chữ số khác 0, 1, 4, 5 và 6 thành các biểu thức đánh giá thành các giá trị bát phân đã nói bằng cách sử dụng $(())và trừ, nối thêm evalvào phía trước. Trong bước cuối cùng của chúng tôi, chúng tôi thêm một cái khác evalvà chuyển đổi dấu ngoặc đơn và dấu trừ thành giá trị bát phân của chúng. Sử dụng phương pháp này, chúng ta có thể thực thi bất kỳ lệnh bash nào, vì vậy tập hợp con này đã hoàn tất.

Thí dụ:

dc trở thành

$'\144\143' trở thành

$'\145\166\141\154' \$\'\\144\\$((144-1))\' trở thành

$'\145\166\141\154' $'\145\166\141\154' $'\$\\\'\\\\144\\\\$\050\050144\0551\051\051\\\''


12

Biến cố , 2 nhân vật

Không có vấn đề gì với hai nhân vật bạn chọn, hoặc; bất kỳ sự kết hợp nào của hai octet đều là Turing-Complete trong Sự cố.

Trên thực tế việc chứng minh điều này khó khăn hơn nhiều so với bạn mong đợi và tại thời điểm viết bài, trang thảo luận về Esolang về Sự cố được dành cho vấn đề. Mặc dù vậy, tôi sẽ cố gắng đưa ra một bản tóm tắt các bằng chứng đơn giản nhất được biết đến dưới đây.

Trước khi chứng minh, một số nền tảng. Sự cố gây ra mã thông báo được sử dụng trong chương trình bằng cách xem nguồn (mã thông báo là chuỗi xuất hiện chính xác ba lần trong nguồn, không phải là chuỗi con của mã thông báo khác và không trùng với mã thông báo tiềm năng khác). Như vậy, bất kỳ chương trình nào cũng có thể được chuyển đổi để sử dụng khá nhiều bộ ký tự bằng cách thay đổi mã thông báo là gì; ngôn ngữ là Turing-Complete (và cũng hoàn chỉnh cho I / O!), mặc dù rất khó lập trình, vì vậy "tất cả" bạn cần là một phương thức mã hóa mã thông báo để chúng hoạt động chỉ với hai ký tự.

Và bây giờ, đây là một bản tóm tắt bằng chứng (được tìm thấy bởi Ørjan, nhà toán học thường trú của Esolang). Ý tưởng là chúng tôi mã hóa mã thông báo bằng cách sử dụng hai bản sao của một ký tự (nói 1) trong một biển lớn của nhân vật kia (nói 0). Khoảng cách giữa các 1s khác cho mỗi thẻ, nhưng luôn luôn là bội số của 4. Sau đó cho đệm giữa các thẻ, chúng tôi sử dụng một danh sách thêm 0s với một 1ở giữa, nhưng số lượng 0s trên mỗi bên của 1không phải là bội số của 4, mà là một số duy nhất cho tỷ lệ cụ thể của chương trình không xuất hiện ở nơi nào khác trong chương trình. Điều đó có nghĩa là mỗi1 ...1trong phần đệm chỉ có thể xuất hiện hai lần, vì vậy sẽ không phải là một phần của mã thông báo; mỗi mã thông báo dự định chứa chính xác hai 1 và không có mã thông báo không có thật nào có thể chứa nhiều hơn một 1. Sau đó, chúng tôi chỉ cần thêm một số phần đệm vào bên cạnh để xóa tất cả các mã thông báo có thể chứa một 1hoặc không 1bằng cách thêm ít nhất bốn bản sao của chúng.


11

Võng mạc , 3 ký tự

{`

và dòng mới.

Trước hết, chúng tôi cần dòng mới để có thể thay thế (cần thiết trừ khi chúng tôi muốn điều chỉnh toàn bộ chương trình thành một regex, cần nhiều ký tự hơn); và `{là cách nhân vật tích cực nhất để làm vòng. Hóa ra chúng ta không cần bất cứ thứ gì khác.

Ngôn ngữ mục tiêu của chúng tôi để triển khai là một biến thể xác định của Thue (tính không đặc biệt không cần thiết cho tính đầy đủ của Turing; có thể viết chương trình Thue để hoạt động chính xác cho dù sử dụng thứ tự đánh giá nào). Ý tưởng cơ bản là biên dịch pattern::=replacementthành

`pattern
replacement

(đó là bản dịch Retina trực tiếp của Thue; thay vào đó, nếu bạn biết Retina nhưng không phải Thue, bạn có thể sử dụng nó như một phương pháp học cách thức hoạt động của Thue); như một ngoại lệ, mẫu đầu tiên được đi trước {`thay vào đó (để đặt toàn bộ chương trình vào một vòng lặp; các chương trình thứ ba tiếp tục chạy cho đến khi không thể thay thế nữa và điều này khiến Retina hoạt động theo cách tương tự).

Tất nhiên, điều này có nghĩa rằng chúng ta cần phải chứng minh Thue Turing hoàn tất chỉ với {`trong các mô hình và thay thế, nhưng đó là đủ đơn giản; chúng tôi thay thế một ký tự bằng mã ascii n bằng `, n +1 {và một ký tự khác `. Rõ ràng là không thể có một mẫu phù hợp với bất cứ nơi nào ngoài ranh giới nhân vật, vì vậy điều này cuối cùng sẽ làm điều tương tự như chương trình gốc.


1
"Các chương trình thứ ba tiếp tục chạy cho đến khi không còn sự thay thế nào nữa và điều này khiến Retina hoạt động theo cùng một cách" với ngoại lệ duy nhất là Retina sẽ chấm dứt sớm nếu một lần đi qua toàn bộ chương trình không thay đổi chuỗi. Vì vậy, bạn thậm chí có được một số phát hiện vòng lặp vô hạn đơn giản miễn phí.
Martin Ender

1
À đúng rồi. Tất nhiên, điều đó không ảnh hưởng đến tính đầy đủ của Turing (vì một vòng lặp vô hạn không thay đổi trạng thái bên trong không thể đóng góp cho lớp tính toán của chương trình).

10

Brachylog , 5 ký tự

~×₁↰|

Tập hợp các ký tự này cho phép chúng tôi triển khai một phiên bản Fractran trong đó các số duy nhất có thể xuất hiện là các sản phẩm của các khoản bồi thường (tức là các sản phẩm của các số có thể được viết bằng số thập phân chỉ bằng chữ số 1). (với một số nguyên dưới dạng chỉ mục) chia giá trị hiện tại cho số nguyên đó, nhưng chỉ khi nó phân chia chính xác (nếu không thì "không thành công" và tìm trường hợp khác để chạy; |tách các trường hợp). ×chúng ta hãy nhân với một số nguyên. Vì vậy, bằng cách sử dụng ~×₁|chúng ta có thể thực hiện một bước thực hiện Fractran. Sau đó cho phép chúng tôi lặp lại, chạy lại toàn bộ chương trình trên giá trị hiện tại mới. Đây là một ví dụ về chương trình Fractran rất đơn giản ( 11111111111111111111111/111) được dịch sang Brachylog.

Vậy Turing này đã hoàn thành chưa? Tất cả những gì chúng ta cần để làm cho Fractran Turing hoàn thành là một số lượng lớn các số nguyên tố đủ lớn (đủ để viết một trình thông dịch cho một ngôn ngữ hoàn chỉnh Turing trong chính Fractran). Có năm đã được chứng minh và bốn nghi ngờhoàn trả các số nguyên tố, ngoài ra, rất có thể, những số chưa được phát hiện. Đó thực sự là nhiều hơn chúng ta cần trong trường hợp này. Chương trình kiểm tra các khả năng từ trái sang phải, vì vậy chúng ta có thể sử dụng một số nguyên tố làm con trỏ chỉ dẫn và hai lần nữa làm bộ đếm, chứng minh tính hoàn chỉnh của Turing chỉ với ba số nguyên tố (một điều tốt là vì nó cho phép chúng ta sử dụng các khoản cộng hưởng với 2, 19 và 23 chữ số, mà không cần phải dùng đến các khoản bồi thường đã được chứng minh nhưng rất khó chịu với 317 hoặc 1031 chữ số, điều này sẽ khiến mã nguồn khá khó viết). Điều đó cho phép thực hiện một máy Minsky với hai bộ đếm (đủ cho tính hoàn chỉnh của Turing).

Đây là cách tổng hợp hoạt động cụ thể. Chúng tôi sẽ sử dụng hai lệnh sau để triển khai máy Minsky của chúng tôi (được biết là hoàn thành Turing) và mỗi lệnh sẽ có một số nguyên dưới dạng nhãn:

  • Nhãn L: Nếu bộ đếm {A hoặc B} bằng 0, goto X. Nếu không thì giảm giá trị và goto Y.
  • Nhãn L: Bộ đếm tăng {A hoặc B}, sau đó goto Z.

Chúng tôi chọn lệnh nào để chạy thông qua việc đặt quyền hạn 11 trong mẫu số, quyền hạn cao nhất trước; số mũ của 11 là nhãn của lệnh. Theo cách đó, phân số đầu tiên khớp sẽ là lệnh hiện đang thực thi (vì các phần trước không thể chia cho tất cả 11 số đó). Trong trường hợp lệnh giảm, chúng tôi cũng đặt một hệ số 111111111111111111 hoặc 111111111111111111111111 trong mẫu số, tương ứng với bộ đếm A hoặc B, và theo dõi nó bằng một lệnh khác không có yếu tố đó; trường hợp "giảm" sẽ được thực hiện bởi lệnh đầu tiên, trường hợp "không" bằng lệnh thứ hai. Trong khi đó, "goto" sẽ được xử lý bởi công suất thích hợp là 11 trong tử số và "gia tăng" thông qua hệ số 11111111111111111111 hoặc 11111111111111111111111111 trong tử số.


Bất kỳ lý do cụ thể nào bạn không thể sử dụng các khoản bồi hoàn theo cặp?
Máy

@CalculatorFeline: Không, nhưng tôi đã không nghĩ về chúng cho đến khi tôi đã tìm thấy công trình không cần đến chúng. Nó chắc chắn sẽ giúp ích trong các chương trình chơi gôn được viết bằng bộ ký tự này.

Ngoài ra, tất cả các khoản hoàn trả> 1 là đồng thời theo cặp (hãy nghĩ về điều đó)
CalculatorFeline

@CalculatorFeline: Không họ không có. 111 và 111111 đều chia hết cho 3, khá rõ ràng.

* không repunit chia một khoản trả lại khác
CalculatorFeline

10

Befunge-98, 3 ký tự

Theo như tôi biết, Befunge-98 được cho là đã hoàn tất, vì vậy chúng tôi chỉ cần cho thấy bất kỳ chương trình Befunge-98 nào có thể được tạo ra chỉ bằng ba ký tự. Giải pháp ban đầu của tôi dựa vào bốn ký tự sau:

01+p

Chúng ta có thể nhận được bất kỳ số nguyên dương nào trên ngăn xếp bằng cách thêm nhiều 1giá trị cùng với +lệnh và với số 0 chúng ta chỉ cần sử dụng 0. Khi chúng tôi có khả năng đẩy bất kỳ số nào chúng tôi muốn, sau đó chúng tôi có thể sử dụngp (đặt) để ghi bất kỳ giá trị ASCII nào vào bất kỳ vị trí nào trong sân chơi Befunge.

Tuy nhiên, như Sp3000 đã chỉ ra, bạn thực sự có thể nhận được chỉ với ba ký tự:

1-p

Bất kỳ số âm nào cũng có thể được tính bằng cách bắt đầu bằng 1và sau đó trừ đi nhiều lần 1(ví dụ: -3 sẽ là 11-1-1-1-). Sau đó, bất kỳ số dương nào cũng có thể được biểu diễn bằng cách trừ 1-n từ 1, trong đó 1-n là số âm mà chúng ta đã biết cách xử lý (ví dụ: 4 = 1 - (- 3), sẽ là111-1-1-1-- ).

Do đó, chúng ta có thể sử dụng ba ký tự của mình để viết một loại bộ nạp khởi động, từ từ tạo mã thực tế mà chúng ta muốn thực thi. Khi trình tải này kết thúc thực thi, nó sẽ chạy vòng quanh đến điểm bắt đầu của dòng đầu tiên của sân chơi, lúc đó sẽ giữ phần bắt đầu của mã mới được tạo của chúng tôi.

Ví dụ, đây là một bộ tải khởi động tạo mã Befunge cần thiết để tính tổng 2 + 2 và đưa ra kết quả: 22+.@

Và đối với một ví dụ phức tạp hơn một chút, đây là "Hello World": "!dlroW olleH"bk,@


Đây là một polyglot, các ký tự tương tự có thể được sử dụng cho> <> và các dẫn xuất của nó. Công việc tốt đẹp!
Sok

2
Befunge-98 là doable trong 3 với 1p-cùng
Sp3000

@ Sp3000 Tất nhiên là có! Tôi chắc chắn phải có một cách để giảm xuống còn 3 ký tự. Cảm ơn.
James Holdiness

9

Ruby, 8 ký tự

eval"<1+

Lấy cảm hứng từ câu trả lời của Python

Làm thế nào nó hoạt động

  • eval có thể được sử dụng để thực thi một chuỗi tùy ý.
  • "<1+ là bộ ký tự tối thiểu cần thiết để xây dựng bất kỳ chuỗi nào

Một chuỗi trong ruby ​​có thể được xây dựng bằng cách sử dụng chuỗi rỗng làm điểm bắt đầu và thêm các ký tự ascii vào chuỗi đó, ví dụ:

eval ""<<111+1<<11+11+11+1<<111<<11+11+11+1

thực sự tương đương với

eval ""<<112<<34<<111<<34

đánh giá chuỗi

p"o"

8

OCaml, 9 ký tự

fun->()`X

Các ký tự này là đủ để thực hiện Tính toán kết hợp SKI trong OCaml. Đáng chú ý là chúng ta có thể tránh việc sử dụng không gian với dấu ngoặc đơn đủ. Thật không may, các biểu thức lambda trong OCaml yêu cầu funtừ khóa nên không thể có giải pháp ngắn gọn hơn. Các chữ cái tương tự có thể được sử dụng để xây dựng các tên biến tùy ý nếu các biểu thức lambda phức tạp hơn được mong muốn.

Kết hợp S:

fun(f)(u)(n)->f(n)(u(n)) với loại ('a -> 'b -> 'c) -> ('a -> 'b) -> 'a -> 'c

Kết hợp K:

fun(f)(u)->u với loại 'a -> 'b -> 'b

Tôi kết hợp:

fun(f)->f với loại 'a -> 'a

Theo ghi nhận của ais523, việc mã hóa SKI là không đủ. Dưới đây là một mã hóa cho Z bằng cách sử dụng các biến thể đa hình để thao tác hệ thống loại. Với tập hợp con của tôi sẽ được hoàn thành.

Kết hợp Z:

fun(f)->(fun(`X(x))->(x)(`X(x)))(`X(fun(`X(x))y->f(x(`X(x)))y))

với loại (('a -> 'b) -> 'a -> 'b) -> 'a -> 'b


2
Công cụ tính toán kết hợp SKI được gõ đơn giản không phải là Turing-Complete; bạn cần một phép tính lambda chưa được đánh dấu cho điều đó. Thật không may, như các cuộc biểu tình của bạn đề cập, OCaml đặt một cách hiểu được gõ vào mã theo mặc định.

1
Sau đó, tôi chỉ cần thêm một vài ký tự để cho phép sử dụng các biến thể đa hình sẽ cho phép mã hóa bộ kết hợp y (và tương tự như bộ kết hợp z).
Devin Lehmacher

Tổ hợp Z là gì?
Máy

@CalculatorFeline Đây là một biến thể nghiêm ngặt của bộ kết hợp y. Nó là cần thiết trong OCaml vì OCaml không lười biếng. Đây là đường dẫn đến trang wikipedia: en.wikipedia.org/wiki/ Kẻ
Devin Lehmacher

8

Ngôn ngữ nối ghép dựa trên ngăn xếp, 4 ký tự

Tải trọng

():^

GolfScript

{}.~

Camam

{}_~

GS2

  • backspace, tab, @space (Tôi biết GS2 đã sử dụng không thể in được rất nhiều, nhưng điều này thật vô lý)

dc (được đề xuất bởi @seshoumara)

[]dx

Underload đã được chứng minh Turing-Complete chỉ với việc sử dụng ():^(nhờ nhà toán học thường trú của Esolang Ørjan). Bằng chứng là quá dài để giải thích ở đây, nhưng nếu bạn quan tâm, bạn có thể đọc về nó ở đây .

Các lệnh trong câu hỏi là ()(đặt mã bằng chữ trên ngăn xếp), :(phần tử ngăn xếp trên cùng trùng lặp) và ^(đánh giá đỉnh của ngăn xếp). Các lệnh này khá phổ biến trong các ngôn ngữ dựa trên ngăn xếp (đặc biệt là các ngôn ngữ ghép nối), và vì vậy tôi đã đưa ra một cái gì đó của một bộ sưu tập chúng ở trên; tất cả các ngôn ngữ này đều hoàn thành Turing trong 4 ký tự với cùng lý do là Underload.


Tôi hiểu rằng bạn có thể thực hiện các thao tác ngăn xếp với những thao tác đó, nhưng bạn không cần ít nhất các số để điền vào ngăn xếp đó để thực hiện các phép tính toán học? Hoặc là những người được thực hiện trong unary sử dụng một trong 4 ký tự?
seshoumara

1
@seshoumara: Các số (và khá nhiều lưu trữ dữ liệu khác) được triển khai rất gián tiếp khi sử dụng phương pháp này. Có một cái gì đó như hai hoặc ba, thậm chí bốn, mức độ trừu tượng trước khi bạn nhận được một cái gì đó dễ nhận biết là số học. Loại điều này là phổ biến trong bằng chứng Turing-đầy đủ của các hệ thống rất hạn chế như thế này.

Tôi đã nghĩ đến việc tự mình gửi một câu trả lời bằng dc, cũng là một ngôn ngữ dựa trên ngăn xếp, nhưng sử dụng một phương thức khác liên quan đến nhiều ký tự hơn 4. dc không có toán tử ghép, nhưng nó có các ngôn ngữ tương đương mà bạn đề cập: [] d x. Có thể dc phù hợp với danh sách của bạn?
seshoumara

@seshoumara: Vâng, có vẻ như nó có tất cả các chức năng cần thiết. Tôi đã thêm nó và ghi có cho bạn.

Có lẽ bạn có thể tra cứu FlogScript
mbomb007

7

Khoảng trắng, 3 ký tự

STL

Slà không gian, Tlà tab và Llà dòng mới.


Đây có phải là ngôn ngữ đầy đủ, hay nó là một tập hợp con? Bằng chứng về sự hoàn thiện của Turing ở đâu?
Brian Minton

2
@BrianMinton Đó là toàn bộ ngôn ngữ, Các wiki esolang rất nhẹ vào nó esolangs.org/wiki/Whitespace nhưng afaik, nó là Turing hoàn chỉnh
Cruncher

7

Vợt (Lược đồ), 4 ký tự

(λ)

Chỉ sử dụng, dấu ngoặc đơn và khoảng trắng, chúng ta có thể lập trình trực tiếp trong tập hợp con Lambda Compus của Scheme. Chúng tôi sử dụng lại ký tự for cho tất cả các mã định danh bằng cách ghép chúng lại với nhau để cung cấp một số lượng lớn các mã định danh duy nhất.

Ví dụ, đây là bộ kết hợp Omega cổ điển, vòng lặp mãi mãi.

((λ (λλ) (λλ λλ)) (λ (λλ) (λλ λλ)))

6

Python 3, 9 ký tự

exc('%1+)

Xem câu trả lời Python 2 của tôi để được giải thích cơ bản. Câu trả lời này được xây dựng trên đó.

Thay vì chỉ sử dụng các ký tự giống như Python hai với việc thêm vào (), chúng ta có thể loại bỏ một ký tự vì bây giờ chúng ta có sử dụng dấu ngoặc đơn. Các chương trình vẫn sẽ có hình dạng cơ bản là

exec('%c'%stuff)

nhưng chúng tôi rút ngắn thời lượng chương trình bằng cách sử dụng +thay vì -và sau đó chúng tôi có thể xóa ~bằng cách sử dụng 1thay vì 0. Sau đó chúng tôi có thể thêm 1, 11111để có được những giá trị ASCII yêu cầu.

Chương trình print()trở thành sau đây ngắn nhất:

exec('%c%%c%%%%c%%%%%%%%c%%%%%%%%%%%%%%%%c%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%c%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%c'%(111+1)%(111+1+1+1)%(11+11+11+11+11+11+11+11+11+1+1+1+1+1+1)%(11+11+11+11+11+11+11+11+11+11)%(111+1+1+1+1+1)%'('%')')

Dùng thử trực tuyến

Bạn có thể tự nghĩ, làm thế nào để tạo một byte NUL mà không có 0? Đừng sợ, châu chấu trẻ! vì chúng ta cũng có khả năng sử dụng %toán học, tạo ra số không với 1%1.


Tại sao bạn muốn có một byte NUL trong chương trình của bạn?
NieDzejkob

@NieDzejkob Trên trang web này, câu trả lời cho "tại sao" luôn là "bởi vì chúng ta có thể". Tuy nhiên, trong trường hợp này, nó sẽ không phải là triển khai đầy đủ của Python nếu bạn không thể làm điều đó, ngay cả khi nó chỉ báo lỗi.
mbomb007

Bạn sẽ không cần một byte NUL cho Turing Complete; một thông dịch viên BF có thể được viết mà không cần một
MilkyWay90

@ MilkyWay90 Đúng, nhưng tại sao không tính đến nó nếu bạn có thể?
mbomb007 ngày

6

PHP 7, 6 ký tự

'().;^

Ý tưởng là có thể thực thi mã tùy ý bằng cách sử dụng cấu trúc sau:

('create_function')('','<code>')();

eval sẽ không hoạt động ở đây, vì đó là cấu trúc ngôn ngữ và không thể được gọi bằng các hàm biến.

create_function và mã có thể được viết dưới dạng ghép các XOR bitwise của các ký tự có sẵn:

(<char1_1>^<char1_2>^...).(<char2_1>^<char2_2>^...)...

Sử dụng ().;^cho <charX_Y>, chúng ta có thể nhận được

()./:;<=JKLMXY^_bcdepqvw

và một số ký tự không thể in được. Điều đó là không đủ, nhưng bây giờ chúng ta cũng có thể gọi 'eXp'()và nhận một số ký tự số:

''.'eXp'('eXp'('')) -> 1
''.'eXp'('eXp'('eXp'(''))) -> 2.718281828459
''.'eXp'('eXp'('eXp'('eXp'('eXp'(''))))) -> 3814279.1047602

Nó cho chúng ta 1, 23(các nhân vật khác sẽ bị bỏ qua bởi XOR, nếu chuỗi khác là một trong những nhân vật dài). Từ ().;^123bây giờ chúng ta có thể tạo tất cả các bảng mã ASCII.

Dùng thử trực tuyến


5

Pyke, 5 ký tự

0h.CE

Điều này có khả năng tạo ra một số lượng lớn vô hạn, biến nó thành một chuỗi và sau đó đánh giá nó là mã Pyke.

Giải thích về mã:

0- Thêm 0 vào ngăn xếp. Điều này là bắt buộc để bắt đầu một số

h- Tăng số trước. Bằng cách lặp lại điều này một số lần tùy ý, bạn có thể tạo ra những con số vô cùng lớn. Pyke hỗ trợ các bignums vì nó được viết bằng Python, sử dụng chúng làm mặc định.

.C - Biến một số thành một chuỗi bằng thuật toán sau: ( Liên kết Github )

def to_string(num):
    string = ""
    while num > 256:
        num, new = divmod(num, 256)
        string = chr(new) + string
    string = chr(num) + string
    return string

Đến thời điểm này, chúng ta có thể tạo ra một số lượng chuỗi và số tự nhiên trong Pyke với các giá trị tùy ý. Các số có thể được tạo ở dạng tương ứng với biểu thức chính quy0(h)* và chuỗi có thể được tạo bằng 0(h)*.C. Chúng có thể được đan xen với nhau để tạo ra một hỗn hợp tùy ý của chuỗi và số nguyên.

E- đánh giá một chuỗi dưới dạng mã Pyke. Điều này sử dụng môi trường giống như mã Pyke đã chạy nên sẽ chia sẻ những thứ như đầu vào.

Cố gắng chứng minh rằng Pyke là Turing Complete.

Một trong những cách đơn giản nhất để thể hiện một ngôn ngữ đang hoàn thiện là bằng cách triển khai Brainf * ck trong đó. Điều này có lẽ khó hơn nhiều ở Pyke so với nhiều ngôn ngữ khác vì danh sách và hoạt động từ điển của nó gần như không tồn tại do không cần chúng trong khu vực Pyke được thiết kế để chạy trong: .

Đầu tiên, chúng tôi tạo một trình thông dịch cho brainf * ck và mã hóa nó bằng thuật toán của chúng tôi ở trên để tạo một số và sau đó thể hiện số đó bằng 0h. Sau đó chúng ta tạo chuỗi chứa mã được chạy theo cùng một cách. Nếu chúng ta để nó ở đó, chúng ta sẽ có ngăn xếp như

string containing brainf*ck code
string containing brainf*ck interpreter

Điều này có nghĩa là mã phải ở dạng ngược lại vì ngăn xếp Pyke là lần đầu tiên xuất hiện cuối cùng.

Bây giờ là phần thú vị: trình thông dịch brainf * ck với con số khổng lồ là 216 byte!

Q~B"><ht.,".:=B;Z]1=L;W~Bo@D=c"ht"{I~c~LZ@EZ]1~LR3:=L)~c\,qIz.oZ]1~LR3:=L)~c\.qI~LZ@.CpK)~c"<>"{I~c"<>""th".:ZE=ZZ1_qI0=Z~L0"":0]10:=L)Z~LlqI~L~Ll"":1_]10:=L))~c\[qI~LZ@0qI\]~B~o>@~o+h=o))~c\]qI~o\[~B~o<_@-t=o)~o~BlN

Hãy thử nó ở đây!

Nếu bạn muốn thử mã ở dạng bán hoàn thành nhưng có thể chỉnh sửa, hãy thử ở đây!

Để chuyển đổi từ một chuỗi thành một số, bạn có thể sử dụng mã Python sau:

def conv(string, t=0):
    t *= 256
    t += ord(string[0])
    if len(string) != 1:
        return conv(string[1:], t)
    return t

Giải pháp (gần như) cuối cùng có thể được thử ở đây!

Giải thích về thông dịch viên Brainf * ck

Đầu tiên cho phép tách chương trình thành các phần:

  • Việc khởi tạo:

Là một tài tài, hay nói, qua, qua, qua một khác, qua giữ, qua, qua một khác, qua, qua, qua, khi khác mới, khác mới, khi khác mới đăng, mới, mới đăng, mới đăng, mới đăng, mới đăng, mới đăng, mới đăng, mới đăng, mới đăng cam cam

Q~B"><ht.,".:=B;Z]1=L; - The initialisation part
Q~B"><ht.,".:          - input.replace("><+-.,[]", "><ht.,")
                       - replace the characters in brainf*ck with some modified ones. 
                       - this means we can `eval` the add and subtract bits easily.
             =B;       - set `B` to this.
                       - The `B` variable contains the instructions
                Z]1=L; - set `L` to [0]
                       - `L` contains the stack, initialised with 0
  • Vòng lặp chính:

Hay nói, là một tài tài của, qua, qua, qua một khác, qua giữ, qua, qua một tài khác, qua, khác qua, qua, khi khác mới mới đăng,, mới mới đăng, mới đăng, mới đăng, mới đăng, mới cam mới, mới đăng, mới đăng, mới đăng ký đăng cam

W~Bo@D=c !code! ~o~BlN - The main loop
W                      - do
 ~Bo@D=c               -  c=B[o++]
                       -  the c variable is used to store the current character.
                ~o~BlN - while
                ~o     -   o 
                     N -  ^ != V 
                  ~Bl  -   len(B)
                       -  this stops the program running once it's finished.
  • Hướng dẫn
    • Tăng / giảm:+-

Hay nói, là một tài tài của, qua, qua, qua một khác, qua giữ, qua, qua một tài khác, qua, khác qua, qua, khi khác mới mới đăng,, mới mới đăng, mới đăng, mới đăng, mới đăng, mới cam mới, mới đăng, mới đăng, mới đăng ký đăng cam

"ht"{I~c~LZ@EZ]1~LR3:=L) - The bit that does incrementing and decrementing
"ht"{I                 ) - if c in "ht"
        ~LZ@             -  L[Z]
                         -  `Z` contains the current stack pointer
      ~c    E            -  eval current character with ^ as an argument
                         -  returns the contents of `Z` either incremented or decremented
             Z]1~LR3:=L  - L[Z] = ^
  • Đầu vào ,::

Hay nói, là một tài tài của, qua, qua, qua một khác, qua giữ, qua, qua một tài khác, qua, khác qua, qua, khi khác mới mới đăng,, mới mới đăng, mới đăng, mới đăng, mới đăng, mới cam mới, mới đăng, mới đăng, mới đăng ký đăng cam

~c\,qIz.oZ]1~LR3:=L) - The code for output 
~c\,qI             ) -  if character == ",":
      z.o            -    ord(input)
         Z]1~LR3:=L  -   L[Z] = ^
  • Đầu ra .::

Hay nói, là một tài tài của, qua, qua, qua một khác, qua giữ, qua, qua một tài khác, qua, khác qua, qua, khi khác mới mới đăng,, mới mới đăng, mới đăng, mới đăng, mới đăng, mới cam mới, mới đăng, mới đăng, mới đăng ký đăng cam

~c\.qI~LZ@.CpK) - The code for input 
~c\.qI        ) - if c == ".":
      ~LZ@      -    L[Z]
          .C    -   chr(^)
            pK  -  print(^)
  • Chuyển sang trái / phải <>::

Hay nói, là một tài tài của, qua, qua, qua một khác, qua giữ, qua, qua một tài khác, qua, khác qua, qua, khi khác mới mới đăng,, mới mới đăng, mới đăng, mới đăng, mới đăng, mới cam mới, mới đăng, mới đăng, mới đăng ký đăng cam

~c"<>"{I~c"<>""th".:ZE=Z - main part 
~c"<>"{I                 - if "<>" in c:
        ~c"<>""th".:     -  c.replace("<>", "th")
                    ZE=Z -  Z = eval(char, Z)

Z1_qI0=Z~L0"":0]10:=L) - lower bound check
Z1_qI                ) - if Z == -1:
     0=Z               -  Z = 0
        ~L0"":         -  L.insert("", 0)
              0]10:=L  -  L[0] = 0

Z~LlqI~L~Ll"":1_]10:=L) - upper bound check
Z~LlqI                ) - if Z == len(L):
        ~Ll"":          -  L.insert("", len(L))
      ~L      1_]10:=L  -  L[-1] = 0
  • Các điều kiện [::

Hay nói, là một tài tài của, qua, qua, qua một khác, qua giữ, qua, qua một tài khác, qua, khác qua, qua, khi khác mới mới đăng,, mới mới đăng, mới đăng, mới đăng, mới đăng, mới cam mới, mới đăng, mới đăng, mới đăng ký đăng cam

~c\[qI~LZ@0qI\]~B~o>@~o+h=o)) - Code for `[`
~c\[qI                      ) - if c == "[":
      ~LZ@0qI              )  -  if L[Z] == 0:
               ~B~o>          -     B[o:]
             \]     @         -    ^.find("]")
                     ~o+h=o   -   o = o + ^ + 1

- Và ]:

Hay nói, là một tài tài của, qua, qua, qua một khác, qua giữ, qua, qua một tài khác, qua, khác qua, qua, khi khác mới mới đăng,, mới mới đăng, mới đăng, mới đăng, mới đăng, mới cam mới, mới đăng, mới đăng, mới đăng ký đăng cam

~c\]qI~o\[~B~o<_@-t=o) - Code for `]`
~c\]qI               ) - if c == "]":
          ~B~o<_       -    reversed(B[:o])
        \[      @      -   ^.find("[")
      ~o         -t=o  -  o = o - ^ -1

5

Xếp chồng lên nhau, 5 ký tự

{!n:}

Đây là ngắn đáng ngạc nhiên. Nếu Stacked có thể thực hiện từng kết hợp SKI, thì đó là Turing Complete. Tóm tắt lại

  • I tổ hợp - chức năng nhận dạng. x -> x
  • K tổ hợp - hàm không đổi. x -> y -> x
  • S tổ hợp - chức năng thay thế. (x, y, z) -> x(z)(y(z))

Tôi kết hợp: {!n}

Bây giờ, cho các chi tiết cụ thể xếp chồng lên nhau. {! ... }là một n-lambda. Đó là một hàm unary có đối số ngầm n. Sau đó, biểu thức cuối cùng được trả về từ hàm. Do đó, {!n}là một hàm lấy một đối số nvà mang lạin .

Tổ hợp K: {!{:n}}

Bây giờ, {:...}là một hàm không có đối số và trả về .... Kết hợp điều này với đội hình n-lambda của chúng tôi, chúng tôi nhận được (thêm khoảng trắng cho rõ ràng):

{! { : n } }
{!         }   n-lambda. arguments: (n)
   { : n }     lambda.   arguments: ()
       n       yields n.

Kết hợp S: {n!nn!nnn:nnn{!n}!nn!nnn{!n}!n!!}

Ok, điều này có vẻ phức tạp hơn một chút. Vì vậy, lambda lấy các đối số, được phân tách bằng các ký tự không định danh. Do đó, lambda trong tiêu đề tương đương với:

{n nn nnn:nnn{!n}!nn!nnn{!n}!n!!}

Đây là một lambda mà mất ba đối số, n, nn, và nnn. Hãy thay thế những việc này với x, yzcho rõ ràng:

{x y z:z{!n}!y!z{!n}!x!!}

Hai {!n}!chỉ là chức năng nhận dạng để một lần nữa tránh khoảng trắng, trong đó !có nghĩa là "thực thi". Vì vậy, một lần nữa, giảm:

{x y z:z y!z x!!}

Với một lời giải thích:

{x y z:z y!z x!!}
{x y z:         }  three arguments
       z y!        apply `y` to `z` -- `y(z)`
           z x!    apply `x` to `z` -- `x(z)`
               !   apply `x(z)` to `y(z)` -- `x(z)(y(z))`

Và do đó, đây là tổ hợp S.


{n nn nnn:nnn{!n}!nn!nnn{!n}!n!!}chứa không gian.
Máy

@CalculatorFeline Bạn đã đọc câu trước đó chưa? Ok, điều này có vẻ phức tạp hơn một chút. Vì vậy, lambda lấy các đối số, được phân tách bằng các ký tự không định danh. Do đó, lambda trong tiêu đề tương đương với:
Conor O'Brien

Oh. (Lưu ý đến bản thân: Ngừng là một thằng ngốc.)
CalculatorFeline
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.