Digraph kullanarak 23 benzersiz karakter. (25 olmadan). UB yok.
Kullanım C ++ sözdizimi başlatıcısı çaprazlı 11 için sıfıra bir tamsayıyı listesi-başlatmak int var{};
kaçınarak =
ve 0
. (Ya da sizin durumunuzda, küreselden kaçınmak iiii
). Bu size global değişkenlerden başka sıfırlar kaynağı verir (yerel ayarların aksine statik olarak sıfıra sıfırlanır).
Mevcut derleyiciler, herhangi bir özel seçeneği etkinleştirmek zorunda kalmadan varsayılan olarak bu sözdizimini kabul eder.
(Tamsayı sarma hüner eğlenceli ve devre dışı optimizasyonu ile golf için Tamam ama imzalı taşma ++ ISO C tanımsız davranıştır. Optimizasyonunu etkinleştirerek, sonsuz döngüler içine bu sarma döngüler dönecek sürece derleme ile gcc / clang -fwrapv
için vermek de taşma tamsayı imzalanmış tanımlanmış davranış: 2'nin tamamlayıcı sarmalaması.
Eğlenceli gerçek: ISO C ++ std::atomic<int>
, iyi tanımlanmış 2'nin tamamlayıcı sargılarına sahiptir! int32_t
tanımlanmışsa 2'nin tamamlayıcısı olması gerekir, ancak taşma davranışı tanımlanmamıştır, bu nedenle bu türlerden birinin 32 bit, dolgu yok ve 2'nin tamamlayıcısı olduğu herhangi bir makine için int
veya bunun için bir typedef olabilir long
.)
Bu özel durum için yararlı değil:
Yeni bir değişkeni, doğrudan başlatma için parantez veya (boş olmayan bir başlatıcı ile) parenler ile mevcut değişkenin bir kopyası olarak da başlatabilirsiniz .
int a(b)
veya int a{b}
şuna eşdeğerdir:int a = b;
Ancak int b();
sıfıra sıfırlanmış bir değişken yerine bir işlev bildirir.
Ayrıca, anonim bir nesnenin sıfırıint()
veya char()
yani sıfır başlatma alabilirsiniz .
Karşılaştırmalarınızı <=
karşılaştırmalar ile <
basit bir mantık dönüşümü ile değiştirebiliriz : döngünün altında değil, karşılaştırmadan hemen sonra döngü sayacı artışını yapın. IMO, insanların önerdiği alternatiflerden daha basittir, örneğin a'nın ++
ilk bölümünde for()
0'a 1 yapmak için kullanmak gibi .
// 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;
}
Biz bunu golf olabilir for(int r{}; r++ < n;)
ama IMO insanlar için okumak daha az kolay. Toplam bayt sayısı için optimizasyon yapmıyoruz.
Eğer zaten kullanıyor h
olsaydık, '
ya da "
bir alanı kurtarabilirdik .
ASCII veya UTF-8 ortamını varsayarsak, uzay char
32 değeri olan bir değerdir. Bunu bir değişkende kolayca oluşturabiliriz, sonracout << 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
Ve diğer değerler, ++
ikili gösterimlerinin bitlerine dayanarak, bir dizi ve iki katından açıkça oluşturulabilir . Yeni bir değişkene iki katına çıkmadan önce LSB'ye 0 (hiçbir şey) veya 1 (++) etkin bir şekilde kaydırılması.
Bu sürüm veya h
yerine kullanır .'
"
Mevcut sürümlerden herhangi birinden çok daha hızlıdır (uzun bir döngüye dayanmaz) ve Tanımsız Davranış içermez . Bu ile herhangi bir uyarı olmadan derler g++ -O3 -Wall -Wextra -Wpedantic
ve birlikteclang++
. -std=c++11
İsteğe bağlı. Yasal ve taşınabilir ISO C ++ 11 :)
Ayrıca küresel değişkenlere de bağlı değildir. Ve bir anlamı olan değişken isimlerle daha insan tarafından okunabilir hale getirdim.
Benzersiz bayt sayısı: 25 , çıkardığım yorumlar hariçg++ -E
. Ve sayacınız gibi boşluk ve satırsonu hariç. sed 's/\(.\)/\1\n/g' ladder-nocomments.cpp | sort | uniq -ic
Bu askubuntu'dan her karakterin oluşumlarını saymak için kullandım ve bunuwc
kaç tane benzersiz karakterim olduğunu saymak için kullandım.
#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;
}
}
Sadece 2 f
karakter for
. Biz kullanabiliriz while
biz bir kullanım vardı yerine eğer döngüler w
.
Döngülerin altına i < r || goto some_label;
koşullu bir atlama yazmak için döngüleri yeniden birleştirebiliriz . (Ama or
yerine kullanmak ||
). Hayır, bu işe yaramıyor. goto
Bir olan deyimi gibi if
bir ifadenin bir alt bileşeni Perl can gibi olamaz. Aksi takdirde, (
ve )
karakterlerini kaldırmak için bunu kullanabilirdik .
Biz satabilseydim f
için g
birlikte if(stuff) goto label;
yerine for
ve sadece normal bir asm gibi altta bir döngü dalı gerekiyordu bu yüzden her iki döngüler daima en az 1 yinelemeyi çalıştırmak do{}while
döngü yapısı. Kullanıcının> 0 bir tamsayı girdiğini varsayarsak ...
Digraflar ve Trigraflar
Neyse ki, ISO C ++ 17'den itibaren trigraflar kaldırıldı, bu nedenle en son C ++ revizyonu için benzersiz golf oynamak ??>
yerine kullanmak }
zorunda değiliz.
Ama sadece özel olarak üç karakterli: ISO C ++ 17 hala gibi digraphs vardır :>
için ]
ve %>
için}
. Yani kullanarak pahasına %
, biz de önleyebilirsiniz {
ve }
ve kullanımı %:
için #
2 daha az sayıda benzersiz karakter net tasarrufu için.
Ve C ++ gibi operatör anahtar kelimelerin yer aldığı not
için !
operatör veya bitor
için |
operatör. İle xor_eq
için ^=
, size bir değişkeni sıfır olabilir i xor_eq i
, ancak kullanmakta değildi birden fazla karakter bulunmaktadır.
Akım g++
zaten üçgeni varsayılan olarak yok sayar -std=gnu++17
; Kullanmak zorunda -trigraphs
veya bunları etkinleştirmek için -std=c++11
bunları içermez ISO standardına uyumdan için falan.
23 benzersiz bayt:
%: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;
%>
%>
Çevrimiçi deneyin!
Son sürümde boşluk ayırıcı '
yerine h
veya "
ayırıcı için tek tırnak kullanılır . Bir char c{}
şeyleri çizmek istemedim, bu yüzden sildim. Bir karakter yazdırmak, bir dize yazdırmaktan daha verimlidir, bu yüzden bunu kullandım.
histogram:
$ 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
Boşluk ayırıcı (hala çözülmemiş)
Şimdi silinmiş bir cevapta, Johan Du Toit özellikle alternatif bir ayırıcı kullanmayı önerdi std::ends
. Bu bir NUL karakteri char(0)
ve çoğu terminalde sıfır genişliğinde yazdırıyor. Sonuç olarak çıktı gibi 1234
görünmeyecekti 1 2 3 4
. Veya daha da kötüsü, sessizce çökmeyen bir şey üzerinde çöple ayrıldı '\0'
.
Rasgele bir ayırıcı kullanabiliyorsanız, rakamın 0
oluşturulması kolay olduğunda cout << some_zeroed_var
. Ama kimse istemiyor 10203040
, bu ayırıcıdan daha kötü.
Kullanmadan veya dize değişmez bir std::string
holding oluşturmak için" "
bir yol düşünmeye çalışıyordum char
. Belki ona bir şey ekliyorlar? Belki de yapıcılardan biri ile 1 uzunluğunda bir tane oluşturduktan sonra []
, ilk baytı bir değere ayarlamak için bir digraf 32
ile?
Johan ayrıca geçerli doldurma karakterini döndüren std::ios
fill () üye işlevini önerdi . Bir akış için varsayılan değer şudur: std::basic_ios::init()
ve ' '
.
std::cout << i << std::cout.fill();
cümledeki << ' ';
ancak kullanımları .
yerine'
.
İle -
biz bir işaretçi alabilir cout
ve kullanım ->fill()
üye işlevi çağırmak için:
std::cout << (bitand std::cout)->fill()
. Ya da değil, biz de kullanmıyorduk, b
bu yüzden &
sözlüksel eşdeğeri yerine de kullanmış olabiliriz bitand
.
Üye işlevini .
veya olmadan çağırma->
Bir sınıfın içine koyun ve tanımlayın 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(); }
}
Sonra ss s{}
döngüden önce ve döngü std::cout << i << s;
içinde. Büyük, bu derler ve düzgün çalışır, ama biz kullanımına vardı p
ve h
için operator char()
, biz kaçınılması en az 1. net kaybı için b
üye işlevlerini yapmak public
kullanarak struct
yerine class
. (Ve protected
herhangi bir yardımcı olması durumunda mirası geçersiz kılabiliriz ).