Golfscript - 12 ký tự
{,1\{)*}/}:f
Bắt đầu với Golfscript - Factorial từng bước
Đây là một cái gì đó cho những người đang cố gắng học golf. Điều kiện tiên quyết là sự hiểu biết cơ bản về golfscript và khả năng đọc tài liệu về golfscript.
Vì vậy, chúng tôi muốn thử chơi golf công cụ mới của chúng tôi . Luôn luôn tốt khi bắt đầu với một cái gì đó đơn giản, vì vậy chúng tôi bắt đầu với giai thừa. Đây là một nỗ lực ban đầu, dựa trên một mã giả mệnh lệnh đơn giản:
# pseudocode: f(n){c=1;while(n>1){c*=n;n--};return c}
{:n;1:c;{n 1>}{n c*:c;n 1-:n;}while c}:f
Khoảng trắng rất hiếm khi được sử dụng trong golfscript. Thủ thuật đơn giản nhất để thoát khỏi khoảng trắng là sử dụng các tên biến khác nhau. Mỗi mã thông báo có thể được sử dụng như một biến (xem trang cú pháp ). Tokens hữu ích để sử dụng như là các biến là các ký tự đặc biệt như |
, &
, ?
- nói chung là bất cứ điều gì không được sử dụng ở những nơi khác trong các mã. Chúng luôn được phân tích cú pháp dưới dạng mã thông báo ký tự đơn. Ngược lại, các biến như n
sẽ yêu cầu một khoảng trắng để đẩy một số vào ngăn xếp sau. Các số về cơ bản là các biến preinitialized.
Như mọi khi, sẽ có những tuyên bố mà chúng ta có thể thay đổi, mà không ảnh hưởng đến kết quả cuối cùng. Trong golfscript, tất cả mọi thứ để đánh giá đúng trừ 0
, []
, ""
, và {}
(xem này ). Ở đây, chúng ta có thể thay đổi điều kiện thoát vòng lặp thành đơn giản {n}
(chúng ta lặp một thời gian bổ sung và chấm dứt khi n = 0).
Như với việc chơi golf bất kỳ ngôn ngữ nào, nó giúp biết các chức năng có sẵn. May mắn là danh sách rất ngắn cho golfscript. Chúng tôi có thể thay đổi 1-
để (
cứu nhân vật khác. Hiện tại mã trông như thế này: (chúng ta có thể sử dụng 1
thay vì |
ở đây nếu chúng ta muốn, điều này sẽ làm giảm việc khởi tạo.)
{:n;1:|;{n}{n|*:|;n(:n;}while|}:f
Điều quan trọng là sử dụng ngăn xếp tốt để có được các giải pháp ngắn nhất (thực hành thực hành thực hành). Nói chung, nếu các giá trị chỉ được sử dụng trong một đoạn mã nhỏ, có thể không cần lưu trữ chúng thành các biến. Bằng cách loại bỏ biến sản phẩm đang chạy và chỉ cần sử dụng ngăn xếp, chúng ta có thể tiết kiệm được khá nhiều ký tự.
{:n;1{n}{n*n(:n;}while}:f
Đây là một cái gì đó khác để suy nghĩ. Chúng tôi sẽ loại bỏ biến n
khỏi ngăn xếp ở cuối thân vòng lặp, nhưng sau đó đẩy nó ngay sau đó. Trong thực tế, trước khi vòng lặp bắt đầu, chúng tôi cũng loại bỏ nó khỏi ngăn xếp. Thay vào đó, chúng ta nên để nó trên ngăn xếp và chúng ta có thể giữ điều kiện vòng lặp trống.
{1\:n{}{n*n(:n}while}:f
Có lẽ chúng ta thậm chí có thể loại bỏ hoàn toàn biến. Để làm điều này, chúng ta sẽ cần phải giữ biến trên ngăn xếp mọi lúc. Điều này có nghĩa là chúng ta cần hai bản sao của biến trên ngăn xếp ở cuối kiểm tra điều kiện để chúng ta không bị mất sau khi kiểm tra. Điều đó có nghĩa là chúng ta sẽ có một dự phòng 0
trên ngăn xếp sau khi vòng lặp kết thúc, nhưng điều đó rất dễ khắc phục.
Điều này dẫn chúng ta đến while
giải pháp vòng lặp tối ưu của chúng tôi !
{1\{.}{.@*\(}while;}:f
Bây giờ chúng tôi vẫn muốn làm cho điều này ngắn hơn. Mục tiêu rõ ràng nên là từ while
. Nhìn vào tài liệu, có hai lựa chọn thay thế khả thi - mở ra và làm . Khi bạn có lựa chọn các tuyến đường khác nhau, hãy thử và cân nhắc lợi ích của cả hai. Mở ra là "khá nhiều vòng lặp", vì vậy, theo ước tính, chúng tôi sẽ cắt giảm 5 ký tự while
xuống còn 4 /
. Đối với do
, chúng tôi cắt giảm while
3 ký tự và hợp nhất hai khối, có thể lưu một hoặc hai ký tự khác.
Thực sự có một nhược điểm lớn khi sử dụng do
vòng lặp. Vì kiểm tra điều kiện được thực hiện sau khi phần thân được thực thi một lần, giá trị của 0
sẽ sai, vì vậy chúng ta có thể cần một câu lệnh if. Bây giờ tôi sẽ nói với bạn rằng mở ra ngắn hơn (một số giải pháp do
được cung cấp ở cuối). Hãy tiếp tục và thử nó, mã chúng tôi đã yêu cầu thay đổi tối thiểu.
{1\{}{.@*\(}/;}:f
Tuyệt quá! Giải pháp của chúng tôi bây giờ là siêu ngắn và chúng tôi đã hoàn thành, phải không? Không. Đây là 17 ký tự và J có 12 ký tự. Đừng bao giờ thừa nhận thất bại!
Bây giờ bạn đang suy nghĩ với ... đệ quy
Sử dụng đệ quy có nghĩa là chúng ta phải sử dụng cấu trúc rẽ nhánh. Thật không may, nhưng như giai thừa có thể được thể hiện một cách đệ quy ngắn gọn, điều này có vẻ như là một sự thay thế khả thi cho phép lặp.
# pseudocode: f(n){return n==0?n*f(n-1):1}
{:n{n.(f*}1if}:f # taking advantage of the tokeniser
Chà điều đó thật dễ dàng - nếu chúng ta đã thử đệ quy trước đó, chúng ta thậm chí có thể không nhìn vào việc sử dụng một while
vòng lặp! Tuy nhiên, chúng tôi chỉ có 16 ký tự.
Mảng
Mảng thường được tạo theo hai cách - sử dụng ký tự [
và ]
ký tự hoặc với ,
hàm. Nếu được thực hiện với một số nguyên ở đầu ngăn xếp, ,
trả về một mảng có độ dài đó với mảng [i] = i.
Để lặp lại qua các mảng, chúng ta có ba tùy chọn:
{block}/
: đẩy, chặn, đẩy, chặn, ...
{block}%
: [đẩy, chặn, đẩy, chặn, ...] (điều này có một số sắc thái, ví dụ: các giá trị trung gian được xóa khỏi ngăn xếp trước mỗi lần đẩy)
{block}*
: đẩy, đẩy, chặn, đẩy, chặn, ...
Tài liệu golfscript có một ví dụ về việc sử dụng {+}*
để tổng hợp nội dung của một mảng. Điều này cho thấy chúng ta có thể sử dụng {*}*
để có được sản phẩm của một mảng.
{,{*}*}:f
Thật không may, nó không đơn giản như vậy. Tất cả các yếu tố được tắt bởi một ( [0 1 2]
thay vì [1 2 3]
). Chúng tôi có thể sử dụng {)}%
để khắc phục vấn đề này.
{,{)}%{*}*}:f
Cũng không hẳn. Điều này không xử lý chính xác bằng không. Chúng ta có thể tính toán (n + 1)! / (N + 1) để khắc phục điều này, mặc dù chi phí này quá nhiều.
{).,{)}%{*}*\/}:f
Chúng ta cũng có thể thử xử lý n = 0 trong cùng một nhóm với n = 1. Đây là thực tế rất ngắn để làm, hãy thử và làm việc ngắn nhất bạn có thể.
Không tốt lắm là sắp xếp, ở 7 ký tự : [1\]$1=
. Lưu ý rằng kỹ thuật sắp xếp này có các mục đích hữu ích, chẳng hạn như áp đặt các ranh giới trên một số (ví dụ: `[0 \ 100] $ 1 =)
Đây là người chiến thắng, chỉ có 3 ký tự:.! +
Nếu chúng ta muốn có số nhân và số nhân trong cùng một khối, chúng ta nên lặp lại trên mọi phần tử trong mảng. Vì chúng tôi không xây dựng một mảng, điều này có nghĩa là chúng tôi nên sử dụng {)*}/
, điều này đưa chúng tôi đến giai đoạn triển khai bản golf ngắn nhất của giai thừa! Với độ dài 12 ký tự, điều này được gắn với J!
{,1\{)*}/}:f
Giải pháp thưởng
Bắt đầu với một if
giải pháp đơn giản cho một do
vòng lặp:
{.{1\{.@*\(.}do;}{)}if}:f
Chúng ta có thể vắt kiệt một vài thứ trong số này. Một chút phức tạp, vì vậy bạn sẽ phải thuyết phục bản thân những công việc này. Hãy chắc chắn rằng bạn hiểu tất cả những điều này.
{1\.!!{{.@*\(.}do}*+}:f
{.!{1\{.@*\(.}do}or+}:f
{.{1\{.@*\(.}do}1if+}:f
Một cách khác tốt hơn là tính toán (n + 1)! / (N + 1), loại bỏ sự cần thiết cho một if
cấu trúc.
{).1\{.@*\(.}do;\/}:f
Nhưng do
giải pháp ngắn nhất ở đây cần một vài ký tự để ánh xạ 0 đến 1 và mọi thứ khác cho chính nó - vì vậy chúng tôi không cần bất kỳ phân nhánh nào. Loại tối ưu hóa này là cực kỳ dễ bỏ lỡ.
{.!+1\{.@*\(.}do;}:f
Đối với bất kỳ ai quan tâm, một vài giải pháp đệ quy thay thế có cùng độ dài như trên được cung cấp tại đây:
{.!{.)f*0}or+}:f
{.{.)f*0}1if+}:f
{.{.(f*}{)}if}:f
* lưu ý: Tôi thực sự chưa kiểm tra nhiều đoạn mã trong bài đăng này, vì vậy hãy thông báo nếu có lỗi.