23 ký tự độc đáo sử dụng Digraphs. (25 không có). Không có UB.
Sử dụng cú pháp khởi tạo giằng C ++ 11 để liệt kê khởi tạo một số nguyên về 0 mà int var{};
tránh =
và 0
. (Hoặc trong trường hợp của bạn, tránh toàn cầu iiii
). Điều này cung cấp cho bạn một nguồn số không khác với các biến toàn cục (được khởi tạo tĩnh thành 0, không giống như các địa phương).
Trình biên dịch hiện tại chấp nhận cú pháp này theo mặc định, mà không phải bật bất kỳ tùy chọn đặc biệt nào.
(Thủ thuật tổng hợp số nguyên rất thú vị và ok khi chơi golf với tối ưu hóa bị vô hiệu hóa, nhưng tràn tràn đã ký là hành vi không xác định trong ISO C ++. Kích hoạt tối ưu hóa sẽ biến các vòng lặp đó thành các vòng lặp vô hạn, trừ khi bạn biên dịch với gcc / clang -fwrapv
để cung cấp tràn số nguyên đã ký hành vi được xác định: gói bổ sung của 2.
Sự thật thú vị: ISO C ++ std::atomic<int>
có sự bao bọc hoàn hảo của 2! int32_t
được yêu cầu phải là phần bù 2 nếu được xác định hoàn toàn, nhưng hành vi tràn không được xác định để nó vẫn có thể là một typedef cho int
hoặc long
trên bất kỳ máy nào có một trong các loại đó là 32 bit, không có phần đệm và phần bù của 2).
Không hữu ích cho trường hợp cụ thể này:
Bạn cũng có thể khởi tạo một biến mới dưới dạng một bản sao của một biến hiện có, với dấu ngoặc nhọn hoặc (với bộ khởi tạo không trống), parens để khởi tạo trực tiếp .
int a(b)
hoặc int a{b}
tương đương vớiint a = b;
Nhưng int b();
khai báo một hàm thay vì một biến được khởi tạo bằng không.
Ngoài ra, bạn có thể nhận được số 0 bằng int()
hoặc char()
, tức là không khởi tạo đối tượng ẩn danh.
Chúng tôi có thể thay thế <=
so sánh của bạn bằng <
so sánh bằng một phép chuyển đổi logic đơn giản : thực hiện tăng số đếm vòng lặp ngay sau khi so sánh, thay vì ở dưới cùng của vòng lặp. IMO điều này đơn giản hơn các lựa chọn thay thế mà mọi người đã đề xuất, như sử dụng ++
trong phần đầu tiên của a for()
để biến 0 thành 1.
// comments aren't intended as part of the final golfed version
int n;
std::cin >> n; // end condition
for(int r{}; r < n;) { // r = rows from 0 .. n-1
++r;
for(int i{}; i < r;) {
++i;
std::cout << i << ' ';
}
std::cout << std::endl;
}
Chúng ta có thể đánh gôn xuống for(int r{}; r++ < n;)
nhưng IMO không dễ đọc cho con người. Chúng tôi không tối ưu hóa cho tổng số byte.
Nếu chúng tôi đã sử dụng h
, chúng tôi có thể tiết kiệm '
hoặc "
cho một không gian.
Giả sử môi trường ASCII hoặc UTF-8, không gian là char
giá trị 32. Chúng ta có thể tạo nó trong một biến đủ dễ dàng, sau đócout << c;
char c{};
c++; c++; // c=2
char cc(c+c+c+c); // cc=8
char s(cc+cc+cc+cc); // s=32 = ' ' = space in ASCII/UTF-8
Và các giá trị khác rõ ràng có thể được tạo ra từ một chuỗi ++
và nhân đôi, dựa trên các bit của biểu diễn nhị phân của chúng. Hiệu quả chuyển 0 (không có gì) hoặc 1 (++) vào LSB trước khi nhân đôi thành một biến mới.
Phiên bản này sử dụng h
thay vì '
hoặc "
.
Nó nhanh hơn nhiều so với một trong các phiên bản hiện có (không dựa vào một vòng lặp dài) và không có Hành vi không xác định . Nó biên dịch không có cảnh báo với g++ -O3 -Wall -Wextra -Wpedantic
và vớiclang++
. -std=c++11
Là tùy chọn. Nó là hợp pháp và di động ISO C ++ 11 :)
Nó cũng không dựa vào các biến toàn cầu. Và tôi đã làm cho nó dễ đọc hơn với tên biến có ý nghĩa.
Số byte duy nhất: 25 , không bao gồm các nhận xét mà tôi đã loại bỏg++ -E
. Và không bao gồm không gian và dòng mới như quầy của bạn. Tôi đã sử dụng sed 's/\(.\)/\1\n/g' ladder-nocomments.cpp | sort | uniq -ic
từ Ubuntu này để đếm số lần xuất hiện của từng nhân vật, và đưa nó vào wc
để đếm xem tôi có bao nhiêu ký tự duy nhất.
#include<iostream>
int main() {
char c{};
c++; c++; // c=2
char cc(c+c+c+c); // cc=8
char s(cc+cc+cc+cc); // s=32 = ' ' = space in ASCII/UTF-8
int n;
std::cin >> n; // end condition
for(int r{}; r < n;) { // r = rows counting from 0
++r;
for(int i{}; i < r;) {
++i;
std::cout << i << s;
}
std::cout << std::endl;
}
}
Chỉ có 2 f
nhân vật là từ for
. Chúng ta có thể sử dụng while
các vòng thay thế nếu chúng ta đã sử dụng w
.
Chúng ta có thể viết lại các vòng lặp thành một kiểu ngôn ngữ lắp ráp i < r || goto some_label;
để viết một bước nhảy có điều kiện ở cuối vòng lặp, hoặc bất cứ điều gì. (Nhưng sử dụng or
thay vì ||
). Không, điều đó không làm việc. goto
là một câu lệnh like if
và không thể là thành phần phụ của biểu thức giống như trong Perl. Nếu không, chúng ta có thể đã sử dụng nó để loại bỏ các ký tự (
và )
.
Chúng tôi có thể giao dịch f
cho g
với if(stuff) goto label;
thay for
, và cả hai vòng luôn chạy ít nhất 1 lần lặp vì vậy chúng tôi chỉ cần một vòng lặp-chi nhánh ở phía dưới, giống như một asm bình thường do{}while
cấu trúc vòng lặp. Giả sử người dùng nhập số nguyên> 0 ...
Digraphs và Tricles
May mắn thay, các bộ ba đã bị xóa kể từ ISO C ++ 17, vì vậy chúng tôi không phải sử dụng ??>
thay vì }
nếu chúng tôi chơi golf duy nhất cho phiên bản C ++ gần đây nhất.
Nhưng chỉ có các bộ ba cụ thể: ISO C ++ 17 vẫn có các sơ đồ như :>
cho ]
và %>
cho}
. Vì vậy, với chi phí sử dụng %
, chúng ta có thể tránh cả hai {
và }
, và sử dụng %:
để #
tiết kiệm ròng ít hơn 2 ký tự duy nhất.
Và C ++ có các từ khóa toán tử như not
cho !
toán tử hoặc bitor
cho |
toán tử. Với xor_eq
cho ^=
, bạn có thể bằng không một biến với i xor_eq i
, nhưng nó có nhiều ký tự mà bạn không sử dụng.
Hiện tại g++
đã bỏ qua các biểu tượng theo mặc định ngay cả khi không có -std=gnu++17
; bạn phải sử dụng -trigraphs
để kích hoạt chúng, -std=c++11
hoặc một cái gì đó để tuân thủ nghiêm ngặt tiêu chuẩn ISO bao gồm chúng.
23 byte duy nhất:
%:include<iostream>
int main() <%
int n;
std::cin >> n;
for(int r<% %>; r < n;) <%
++r;
for(int i<%%>; i < r;) <%
++i;
std::cout << i << ' ';
%>
std::cout << std::endl;
%>
%>
Hãy thử trực tuyến!
Phiên bản cuối cùng sử dụng một '
trích dẫn duy nhất thay vì h
hoặc "
cho dấu phân cách không gian. Tôi không muốn trình bày char c{}
nội dung nên tôi đã xóa nó. In một char hiệu quả hơn in một chuỗi, vì vậy tôi đã sử dụng nó.
Biểu đồ:
$ sed 's/\(.\)/\1\n/g' ladder-nocomments.cpp | sort | uniq -ic | tee /dev/tty | wc -l
15 // newline
95 // space
11 %
2 '
3 (
3 )
4 +
9 :
10 ;
14 <
8 >
2 a
4 c
6 d
3 e
2 f
12 i
2 l
2 m
11 n
5 o
7 r
5 s
11 t
3 u
25 // total lines, including space and newline
Dấu phân cách không gian (vẫn chưa được giải quyết)
Trong một câu trả lời hiện đã bị xóa, cụ thể là Johan Du Toit đã đề xuất sử dụng một dấu phân cách thay thế std::ends
. Đó là một ký tự NUL char(0)
và in dưới dạng độ rộng bằng không trên hầu hết các thiết bị đầu cuối. Vì vậy, đầu ra sẽ như thế nào 1234
, không 1 2 3 4
. Hoặc tệ hơn, bị ngăn cách bởi rác trên bất cứ thứ gì không âm thầm sụp đổ '\0'
.
Nếu bạn có thể sử dụng một dấu tách tùy ý, khi chữ số 0
dễ tạo cout << some_zeroed_var
. Nhưng không ai muốn 10203040
, điều đó thậm chí còn tệ hơn là không có dải phân cách.
Tôi đã cố gắng nghĩ ra một cách để tạo ra một std::string
tổ chức" "
mà không cần sử dụng char
hoặc một chuỗi ký tự. Có thể nối thêm một cái gì đó cho nó? Có thể với một sơ đồ []
để đặt byte đầu tiên thành giá trị của 32
, sau khi tạo một byte có độ dài 1 thông qua một trong các hàm tạo?
Johan cũng đề xuất std::ios
hàm thành viên fill () trả về ký tự điền hiện tại. Mặc định cho một luồng được đặt bởi std::basic_ios::init()
và là ' '
.
std::cout << i << std::cout.fill();
thay thế << ' ';
nhưng sử dụng .
thay vì'
.
Với -
, chúng ta có thể lấy một con trỏ tới cout
và sử dụng ->fill()
để gọi hàm thành viên :
std::cout << (bitand std::cout)->fill()
. Hoặc không, chúng tôi không sử dụng b
hoặc vì vậy chúng tôi cũng có thể đã sử dụng &
thay vì tương đương từ vựng của nó , bitand
.
Gọi một chức năng thành viên mà không có .
hoặc->
Đặt nó trong một lớp và định nghĩa operator char() { fill(); }
// not digraphed
struct ss : std::ostream { // default = private inheritance
// ss() { init(); } // ostream's constructor calls this for us
operator char() { return fill(); }
}
Sau đó ss s{}
trước vòng lặp, và std::cout << i << s;
bên trong vòng lặp. Tuyệt vời, nó biên dịch và hoạt động đúng, nhưng chúng tôi đã phải sử dụng p
và h
cho operator char()
, vì mất ròng 1. Ít nhất chúng tôi đã tránh b
thực hiện các chức năng thành viên public
bằng cách sử dụng struct
thay vì class
. (Và chúng tôi có thể ghi đè lên phần thừa kế protected
trong trường hợp có ích).