Problem polega na tym, że wiele języków jest (często krótkotrwałych) eksperymentalnych z bardzo nietypowymi paradygmatami, dla których typowe wyrażenia programistyczne nie mają żadnego sensu. Tak więc „większość wszystkich języków” jest praktycznie niemożliwa do spełnienia. Powinieneś ograniczyć to w jakiś sposób, np. Do „większości języków regularnie używanych na codegolf.SE”. W tej chwili odpowiedzi wyglądają bardzo podobnie do „większości zdalnie języków pochodzących z języka C”, ale te, choć znaczna większość całego napisanego w nich kodu , nie są większością języków .
przestał obracać przeciwnie do zegara
3
po lewej, chyba wszyscy wiemy, co mniej więcej oznaczają. Chodzi głównie o optymalizacje niezależne od języka, tj. Te nie tylko przydatne w Brainfuck, ale może jednocześnie Python, C, Java i Fortran. Ogólne pomysły, które można zastosować w wielu językach, które działają podobnie. Nie sądzę, że trzeba być tak precyzyjnym i konkretnym w poradach i pytaniu CW. Chodzi o pomaganie innym w golfa, a nie wkurzanie ich.
Joey,
14
Mam nadzieję, że nikt nie tworzy języka o nazwie <all languages>...
mbomb007
Odpowiedzi:
72
Scal pętle
Zwykle można scalić dwie konsekwentne pętle lub dwie zagnieżdżone pętle w jedną.
Przed:
for (i=0; i<a; i++) foo();
for (i=0; i<b; i++) bar();
ugoren pętle wciąż nie są takie same. @ Gaffi ma rację.
kaoD
5
@kaoD, w obu przypadkach foonazywa się arazy, barnazywa się brazy. Wynika to z faktu, że w trybie „po” pętla działa a+brazy, pierwsze awywołanie foo, następne wywołanie bar.
ugoren
Patrzę na to jeszcze raz (znacznie, dużo później) i nie rozumiem teraz mojego pytania. Może wcześniej nie rozumiałem operacji trójskładnikowej? To, co widzę teraz, ma sens.
Gaffi,
1
Ups, przeczytałem to bardzo późno w nocy. Masz rację!
kaoD
3
Bardzo podobne: for(y=0;y<Y;++y)for(x=0;x<X;++x)często może stać się for(i=0;i<X*Y;++i)z xwyrazami i%Xi yzastąpione i/X.
Lynn
62
Wystarczy wspomnieć o oczywistym:
Podważ swój wybór algorytmu i wypróbuj coś zupełnie nowego.
Podczas gry w golfa (szczególnie trudniejsze problemy, które skutkują dłuższymi programami) zbyt często możesz trzymać się wybranej ścieżki, nie wypróbowując innych podstawowych opcji. Oczywiście możesz zagrać w mikro golfa na raz lub kilka linii na raz lub część ogólnego pomysłu, ale często nie próbujesz zupełnie innego rozwiązania.
Było to szczególnie widoczne w Uderzeniu 495 (Kaprekar), gdzie odbieganie od faktycznego algorytmu i szukanie wzorców, które można zastosować, aby uzyskać ten sam wynik, było krótsze w wielu językach (tylko nie J).
Minusem jest to, że prawdopodobnie rozwiązujesz to samo pół tuzina razy. Ale działa we wszystkich językach oprócz HQ9 + (gdzie znalezienie innego sposobu na wyświetlenie Hello World byłoby nieco daremne).
+1 Oprócz tego, że jest dobry do gry w golfa, jest to dobre ćwiczenie dla każdego programisty w wielu rzeczywistych sytuacjach!
Gaffi,
52
Użyj rozwoju opartego na testach
Jeśli kod musi obsługiwać różne dane wejściowe, napisz kompleksowe testy i bardzo szybko uruchom je wszystkie. Pozwala to wypróbować ryzykowne transformacje krok po kroku. Gra w golfa staje się wtedy jak refaktoryzacja z przewrotną intencją.
Korzystam z podziału tej metody. Ponieważ same problemy są zwykle dość proste, piszę program, który wykonuje tę pracę. Zwykle jest to „czytelnie gra w golfa”, więc jest zwięzłe, ale pojawiają się nowe linie itp. Kopiuję ten plik do nowej lokalizacji i sprawdzam go, sprawdzając co jakiś czas, czy programy zwracają te same wartości dla wybranych danych wejściowych. Jeśli kiedykolwiek popełniam błąd, zostawiając mnie zepsutym programem, bez pamięci o tym, co zmieniłem i bez zrozumienia mojego golfa, mam coś w rodzaju „specyfikacji” zapisanej jako źródło odniesienia.
shiona
2
Uwielbiam tę metodę, dlatego często dołączam kompleksowe pakiety testowe do wszystkich pisanych przeze mnie problemów.
Joey,
@RubberDuck Zasada Nie powtarzaj się jest często ściśle przestrzegana.
Jonathan Frech
48
Spróbuj zmniejszyć logiczne instrukcje
Na przykład, jeśli Ai Bsą wartościami logicznymi, a Twój język traktuje wartości logiczne w pewnym stopniu A and (not B)i A>Bsą one równoważne. Na przykład w Pythonie
B>A or foo()byłoby jeszcze krótszym sposobem na wyrażenie tego, skorzystaj z leniwej oceny wyrażeń boolowskich, aby upewnić się, że oblicza rzeczy tylko wtedy, gdy jest to konieczne.
scragar
5
@scragar: Prawidłowo, ale nie o to chodzi w tym poradniku. (Jest to jednak cenna niezależna wskazówka).
Wrzlprmft
3
@scragar, B>A or fooocenia, fooczy B==Anie tego chcemy. (Racja?)
msh210
2
Ponadto, jeśli masz długie zaabsorbowane warunki (powiedzmy z parametrami 5/6), możesz użyć tabeli Prawdy i mapy Karnaugh, aby znaleźć najkrótsze boolowskie wyrażenie dla niej
Katenkyo
33
Zainicjuj zmienne przy użyciu wartości, które już masz.
Zamiast tego x=1spróbuj poszukać czegoś, co już jest równe 1.
Na przykład wartość zwracana przez funkcję: printf("..");x=0;-> x=!printf("..");. Najłatwiej jest z 0, ponieważ zawsze możesz zanegować lub gdy wszystko, czego potrzebujesz, to właściwa wartość prawdy (i nie przejmuj się, czy jest to 1 czy 19).
@ std''OrgnlDave, prawda, ale to pytanie dotyczy rzeczy wspólnych dla wszystkich języków.
ugoren
33
Użyj unary ~dla x+1ix-1
Ta sztuczka dotyczy języków, w których występuje jednoargumentowy operator negacji bitowej ~i jeden zwykły operator negacji -.
Jeśli Twój program przypadkowo zawiera wyrażenie -x-1, możesz je zastąpić, ~xaby zapisać bajty. Nie zdarza się to zbyt często, ale uważaj, co się stanie, jeśli negujemy ( -) oba wyrażenia: x+1równa się -~x! Podobnie x-1jest równy ~-x. (Zastanów się, w którą stronę wskazuje tylda: prawa jest +, lewa jest -.)
Jest to przydatne, ponieważ we wszystkich językach, o których myślę, że mają te operatory, mają wyższy priorytet niż większość operatorów. Pozwala to zaoszczędzić na nawiasach. Zobacz, jak zapisujemy tutaj cztery bajty:
Poznaj zasady dotyczące białych znaków w swoim języku. Niektóre znaki interpunkcyjne lub inne znaki mogą nie wymagać otaczających białych znaków. Rozważ tę funkcję powłoki Bourne'a :
f () { echo a; echo b; }
W powłoce Bourne'a ();są metaznakami i nie potrzebują otaczających białych znaków. Są {}to jednak słowa i wymagają spacji, chyba że znajdują się obok metaznaków. Możemy zagrać w golfa 4 pola obok ();, ale musimy zachować przestrzeń pomiędzy {i echo.
f(){ echo a;echo b;}
W Common Lisp i PicoLisp , ()są metaznakami. Rozważ ten kod, aby znaleźć średnią dwóch liczb:
(/ (+ a b) 2)
Możemy zagrać w golfa na 2 pola.
(/(+ a b)2)
Niektóre języki mają dziwne i subtelne reguły dotyczące białych znaków. Rozważ ten program Ruby, który wypisuje sumę i iloczyn linii liczb całkowitych.
Każdy &potrzebuje miejsca przed sobą. W Ruby i=$F.map &:to_ioznacza, i=$F.map(&:to_i)gdzie &przekazuje parametr bloku. Ale i=$F.map&:to_ioznacza, i=$F.map.&(:to_i)gdzie &jest operator binarny.
Ta dziwność zdarza się w językach takich jak Perl czy Ruby, które używają niejednoznacznych znaków interpunkcyjnych. W razie wątpliwości użyj REPL lub napisz krótkie programy, aby przetestować reguły białych znaków.
Dlaczego między „{” a „echo” musi być spacja, ale nie między „;” i „echo”?
Ryan,
3
Użyłem terminów z podręcznika dla OpenBSD sh (1), który mówi, że „{” jest słowem zastrzeżonym, a „;” jest meta-postacią. Z tego powodu „{echo” to jedno słowo, ale „; echo” to dwa słowa. Inne podręczniki mogą to wyjaśniać inaczej. Ponadto, Zsh shell Z ma inne zasady.
kernigh
28
przypisuj funkcjom nowe nazwy, jeśli są używane wielokrotnie
x = SomeLongFunctionName
x(somedata)
x(somemoredata)
etc
Tylko jeśli użyjemy wystarczającej liczby połączeń z x.
elipszilon
28
Nazwy zmiennych jednoliterowych
Masz ich 52; użyj ich wszystkich! Nie bój się wypróbować różnych metod i porównać długości. Zna język i konkretne dostępne skróty / funkcje biblioteczne.
26 dla języków bez rozróżniania wielkości liter. :-)
Gaffi
12
Często $i _mogą być używane jako identyfikatory.
Griffin
4
@Gaffi: I więcej niż wystarcza dla języków, które pozwalają na identyfikatory Unicode, chyba że zadanie ogranicza Cię do ASCII lub liczy bajty zamiast znaków.
hammar
Jeśli liczysz bajty zamiast Unicode, to użycie rozszerzonego ascii może być sposobem na wyciśnięcie kolejnych ~ 120 identyfikatorów, jeśli ich potrzebujesz (nie że w przypadku skryptu golfowego powinieneś potrzebować więcej niż 26)
Scragar
2
@jest poprawną nazwą zmiennej w T-SQL, użyj jej zamiast @a.
BradC
25
Użyj operatora warunkowego.
Operator warunkowy
bool ? condition_true : condition_false
jest bardziej korzystne, charakter mądry, niż IF oświadczenie .
Napisanie wyjaśnienia zmusza cię do dokładnego spojrzenia na każdą część kodu i do wyrażenia swoich myśli i wyborów przy pisaniu określonego fragmentu. W ten sposób może się okazać, że możliwe są różne podejścia, które mogą zaoszczędzić niektóre bajty, lub że podświadomie przyjęliście założenia, które niekoniecznie się utrzymują.
Ta wskazówka jest podobna do Pytanie o wybór algorytmu i wypróbuj coś zupełnie nowego ; odkryłem jednak, że krok polegający na spisaniu, w jaki sposób ma działać każda część, jest czasem kluczowy dla uświadomienia sobie alternatyw.
Jako bonus, odpowiedzi zawierające wyjaśnienia są bardziej interesujące dla innych użytkowników i dlatego są bardziej prawdopodobne, że zostaną ocenione.
Brzmi jak oczywisty, ale uważając, możesz być w stanie „uratować” kilka postaci, nie robiąc nic!
Jeśli używasz systemu Windows, możesz wprowadzać dane \r\nzamiast po prostu \rlub \npo naciśnięciu klawisza Return - dodając dodatkowy bajt na wiersz! Przekręć znaki kontrolne, aby podwójnie sprawdzić, czy tego nie robisz.
W Notepad ++ można przekonwertować wszystkie \r\nzakończenia linii, \rprzechodząc do Edit > EOL Conversion > UNIX/OSX Format.
Upewnij się także, że nie dołączasz żadnych białych znaków do liczby postaci! Przesuw wiersza w dolnej linii kodu również nie ma znaczenia, więc nie trzeba go też liczyć.
Nie sądzę, że kiedykolwiek widziałem przypadek, w którym to się naprawdę liczyło ...
Jacob
4
Właśnie miałem ten problem (dlatego go dodaję).
Sean Latham
21
Przeczytaj uważnie pytanie
Gra w golfa kodowego polega zarówno na zrozumieniu pytania (co jest zadawane, a czego nie zadawane, nawet jeśli byłoby to sugerowane w innych ustawieniach), jak na tworzeniu kodu, który (może) zaspokoi tylko to, o co pytamy.
Wszelkie dane wejściowe inne niż jawnie wymagane nie muszą być przetwarzane. Jeśli istnieją pewne przypadki testowe i nie ma ogólnych wymagań, kod może działać tylko w tych przypadkach. Itp.
Myślę, że lepszym nagłówkiem byłoby „Nie zajmuj się niepotrzebnymi przypadkami krawędzi”. Wyrażenie „Spróbuj znaleźć luki” przywodzi na myśl sposoby unikania robienia tego, co jest określone przez jakąś pomysłową reinterpretację zasad, podczas gdy to, co oferujesz, jest jedynie dobrą radą, aby nie nadmiernie wdrażać rozwiązania.
Jonathan Van Matre
1
Tak, ale pomysłowa interpretacja zasad jest również częścią gry w golfa! (0 rozwiązań char itp.)
Tobia,
8
To powinna / powinna być inna odpowiedź. Istnieje podstawowa różnica między, na przykład, wdrożeniem rozwiązania, które działa tylko dla ints, ponieważ OP nie wymagało obsługi zmiennoprzecinkowej, a odpowiedzią, która wypisuje tekst „dowolna liczba pierwsza większa niż 100”, ponieważ „nie powiedziałeś, że trzeba być rzeczywistą liczbą pierwszą ”.
Jonathan Van Matre
Myślę, że niektóre OP zawierają komunikat „Przypadki testowe mogą ulec zmianie; Twój kod musi nadal działać po zmianie” i naprawdę je zmienić, jeśli zobaczą tylko jedną odpowiedź, która koduje przypadki testowe.
Erik the Outgolfer,
20
Użyj operacji bitowych do sprawdzania liczb od 0 do dowolnych 2 n -1
Może to być trochę ostry futerał, ale czasami może się przydać. Opiera się na fakcie, że wszystkie liczby, których dotyczy m = 2 n -1, mają skrajnie prawe n bitów ustawione na 1.
Tak więc 7 10 == 00000111 2 , 15 10 == 00001111 2 , 31 10 == 00011111 2 i tak dalej.
Sztuką jest x&~m. Zwróci wartość true, gdy niex jest pomiędzy 0 a (włącznie), a false w przeciwnym razie. Zapisuje 6 bajtów od następnego najkrótszego równoważnego wyrażenia :, ale oczywiście działa tylko wtedy, gdy spełnia 2 n -1.mx>=0&&x<=mm
Na przykład w C twoja funkcja główna zawsze przekazuje liczbę argumentów dostarczonych do programu (czyli 1 - nazwa programu - domyślnie), więc main(i){...masz teraz zmienną o wartości 1 bez konieczności wykonywać dowolne zadania. 2 znaki tam zapisane.
Griffin
6
Myślę, że jest to dość specyficzne dla C. Skrypty nie potrzebują deklaracji, aw większości skompilowanych języków zdefiniowanie zmiennej nie jest dłuższe niż zdefiniowanie parametru.
ugoren
w Javie, gdy potrzebna jest tablica wewnątrz funkcji tego samego typu co jeden parametr, można zaoszczędzić kilka bajtów, umieszczając ten parametr jako ostatni i czyniąc go parametrem vararg; (użył tego, aby
Nie jestem pewien, czy rozumiem o co chodzi. Co to zmniejsza?
Gaffi
@ Gaffi, zapisujesz jedną postać i robią dokładnie to samo
ajax333221
vs. jaka alternatywa? Przepraszam, nie próbuję być uparty, po prostu tego nie rozumiem. (newb, tutaj, najwyraźniej ...)
Gaffi
1
O, rozumiem. Działa na dowolnym przejściu liczb całkowitych z 9 na 10, 99 na 100 itd. Przepraszam, że zajęło mi to tak długo! (Mówię tylko liczbę całkowitą, ponieważ widzę problem z n = 9,5 ...)
Gaffi
8
Również w niektórych językach (jeśli są obsługiwane), jeśli twoje liczby są wystarczająco duże / małe, notacja naukowa może faktycznie zaoszczędzić ci kilka znaków: if(n>99999)vsif(n<1e5)
scragar
16
Użyj> i <zamiast> = i <=
Podczas sprawdzania z zakodowanymi liczbami całkowitymi wartości, użyj >oraz <zamiast >=i <=gdzie to możliwe. Na przykład za pomocą
Powiązane: Jeśli masz pewność, że wynik nie może być ujemny, możesz użyć <1zamiast kontroli ==0zerowej (lub >0zamiast !=0kontroli lustrzanej).
Kevin Cruijssen
1
Czy nie powinieneś dodać uwagi o xbyciu liczbą całkowitą?
Zacharý
15
Unikaj przedwczesnych przerw w pętli
Jeśli biegnie się przez pętlę, aby sprawdzić 1 lub więcej wystąpień kontroli boolowskiej, może to sprawić, że wydajniejszy program może wyjść z pętli na pierwszej prawdziwej wartości. Jednak usunięcie przerwy i zapętlenie wszystkich iteracji pozwala na skrócenie kodu.
int main() {
bool m = false;
int n = 1000;
for (int i = 0; i < n; i++) {
if (i >= 100) {
m = true;
break; // remove this line
}
}
return 0;
}
Można również uprościć ifoświadczenie daleko w tych przypadkach: m|=i>=100. (I można również uprościć i>=100, aby i>99w tym przypadku, ale nie jest to bardzo istotne tutaj)
Marinus
15
użyj -zamiast!=
dla porównań numerycznych:
Jeśli a jest równe b, a-bpowstaje 0, co jest fałszem. Wszystko inne niż 0jest prawdą; więc
jeśli jest używany w kontekście logicznym, a-b<=>a!=b
Jeśli używasz go razem if/elsez operatorem trójskładnikowym, może to również zaoszczędzić jeden bajt dla równości: a==b?c:d<=>a-b?d:c
Większość języków ma sposób na podzielenie łańcucha na tablicę łańcuchów wokół jakiegoś tokena. Będzie to nieuchronnie krótsze niż literał tablicowy, gdy długość osiągnie próg zależny od języka, ponieważ dodatkowy narzut na łańcuch będzie jedną kopią tokena o jednym znaku, a nie (przynajmniej) dwoma ogranicznikami łańcucha.
Np. W GolfScript
["Foo""Bar""Baz""Quux"] # 23 chars
staje się
"Foo
Bar
Baz
Quux"n/ # 20 chars
W niektórych językach próg jest tak niski jak jeden ciąg. Np. W Javie
Godnym uwagi wyjątków Ruby, który stanowi tablicę-of-ciągi dosłownych automatycznie Dzieli przestrzeniami kosztem dwóch bajtów: %w{Foo Bar Baz Quux}.
Martin Ender
1
Perl zapewnia coś podobnego: qw(Foo Bar Baz Quux)staje się listą ciągów znaków.
BenGoldberg,
12
Zrozum, co zrobili inni ludzie
Oprócz zabawy, gdy badasz kod innych osób, możesz czasem odkryć dobry algorytm, o którym nie pomyślałeś, lub sztuczkę (czasem oczywistą), którą przeoczysz.
Czasami istnieje odpowiedź, którą można przetłumaczyć na inny język i skorzystać z zalet tego drugiego języka.
Ilekroć połączysz kilka wyrażeń, sprawdź tabelę priorytetów operatora dla swojego języka, aby zobaczyć, czy możesz zmienić kolejność rzeczy, aby zapisać nawiasy.
Przykłady:
We wszystkich językach, które znam, operatory bitowe mają wyższy priorytet niż operatory logiczne:
(a&b)&&cnie wymagają nawiasów: a&b&&ctak jak (a*b)+cnie.
a+(b<<c)można przepisać jako a+b*2**c.
To nie oszczędza niczego dla tego przykładu, ale będzie, jeśli cjest to mała literałowa liczba całkowita (<14).
Operacje bitowe mają niższy priorytet niż większości operacji arytmetycznych, więc jeśli Twój język pośrednio rzuca logiczną do int, można zapisać bajt na a<b&&c<dz a<b&c<d(chyba trzeba krótką ocenę obwodu)
Jeśli masz Xinstrukcje {wewnątrz }pętli for, możesz przenosić X-1instrukcje (wewnątrz )pętli for po drugim średniku, for(blah;blah;HERE)aby zapisać 3 bajty. (rozdziel instrukcje za pomocą przecinka ,)
Zamiast
for(int i=0;i<9;){s+=s.length();println(i++);}
możesz przenieść jedną z instrukcji do (nawiasów klamrowych for-loop, )a drugą pominąć
for(int i=0;i<9;println(i++))s+=s.length();
i zapisz 3 bajty (zapisałeś 1 bajt więcej dzięki @ETHProductions)
Może to wyglądać na wskazówkę, której nie będziesz używać tak często, tak jakby używanie ~xzamiast -x-1nie zdarzało się często, ale użyłem jej wystarczająco dużo razy, aby uznać ją za przydatną wskazówkę. Zwłaszcza w przypadku indeksowania tablic w niektórych przypadkach możesz użyć ich powyżej.
Prosta sztuczka, którą wymyśliłem, próbując wycisnąć długą serię warunków połączonych przez ands (lub ors, w tym przypadku po prostu zamień „all” na „any”).
Które języki mają all(array-of-Booleans)wbudowane?
Peter Taylor
3
Ruby to ma. [a>0,a<10,a+b==4,a+3<1].all?
kernigh,
4
Chociaż gdyby to był Python, if 10>a>0 and a+b==4>1>a+3:
użyłbyś
@PeterTaylor Haskell też ma
dumny haskeller
6
Polegaj na kompilatorze, aby zapewnić wymaganą wydajność.
Pamiętaj, które optymalizacje są gwarantowane przez kompilator i na jakich poziomach optymalizacji, i używaj ich swobodnie. A nawet jeśli wydajność nie jest problemem wymóg, nadal można przetestować z optymalizacji sprawie, i to tylko dlatego, że jeden znak zniżka kod jest wciąż technicznie poprawny bez flagi kompilatora.
Rozważ następującą funkcję Haskella, aby obliczyć 2 ^ n (ignorując fakt, że Haskell ma już wbudowany operator potęgowania lub trzy) (23 znaki):
p 0=1;p x=p(x-1)+p(x-1)
Problem w tym, że jest strasznie powolny, działa w wykładniczym czasie. Może to spowodować, że Twój kod będzie niestabilny lub nie spełnią żadnych ograniczeń wydajności podanych w pytaniu. Możesz skusić się na użycie zmiennej tymczasowej lub bezpośrednio wywołanej literału funkcji, aby uniknąć powtarzających się wywołań funkcji (25 znaków):
p 0=1;p x=(\y->y+y)$p$x-1
Ale kompilator może już to zrobić, wystarczy ustawić -Ojako flagę kompilatora! Zamiast wydawać kilka dodatkowych znaków na witrynę, aby ręcznie wyeliminować typowe podwyrażenia, po prostu powiedz kompilatorowi, aby wykonał podstawowe optymalizacje dla ogólnej liczby jednego lub dwóch znaków w całym programie.
W jakim języku możesz wykonywać zadania w ramach połączenia? czy to jest słowo kluczowe arg?
kot
2
Myślę, że przypisania są wyrażeniami (z nową wartością przypisanej zmiennej jako ich wartością wyrażenia) w co najmniej C, C ++, C # i Javie. a = (b=c)+1;ustawia bna c, a następnie ustawia ana b+1.
Lynn,
@Lynn Try a=1+b=c. Możesz dodać PHP i JavaScript do swojej listy.
Tytus
2
Ruby robi to najlepiej. Daje =operatorowi wyższy priorytet po lewej niż po prawej stronie, więc 1+x=2jest ważny i ocenia na3
Cyoce
@Cyoce afaik jest tak we wszystkich językach, w których przypisanie jest wyrażeniem.
Tytus
5
Wykorzystaj wersję językową / kompilator / dziwactwa środowiskowe / nowe funkcje
Jest to szczególnie przydatne w przypadku poliglotów , ale można je zastosować do innych wyzwań. Czasami błąd kompilatora może odejść od bajtu, błąd implementacji może pozwolić Ci zaoszczędzić kilka znaków lub naprawdę najnowocześniejsza funkcja może poprawić twój wynik.
Ponadto użyj bitowych warunków ( &, `|), aby usunąć więcej znaków.
FUZxxl,
2
Chociaż użycie bitowe &zamiast &&usuwać 1 znak w niektórych przypadkach zaburza pierwszeństwo operatora i będziesz musiał umieścić nawiasy, aby działało. Użyj go mądrze.
DollarAkshay
4
Znajdź lepsze sposoby inicjalizacji zmiennych
Kilka innych odpowiedzi już prawie o tym wspomniało, ale w wielu językach (ściśle wpisanych?) Inicjowanie xjako pusty ciąg znaków jest krótsze :
x:=""
lub xjako pusta runa (char) jak:
x:=''
niż
var x string
i
var x rune
Korzystanie z istniejących wartości jest oczywiście preferowane, ale nie takie łatwe.
<all languages>
...Odpowiedzi:
Scal pętle
Zwykle można scalić dwie konsekwentne pętle lub dwie zagnieżdżone pętle w jedną.
Przed:
Po:
źródło
foo
nazywa sięa
razy,bar
nazywa sięb
razy. Wynika to z faktu, że w trybie „po” pętla działaa+b
razy, pierwszea
wywołaniefoo
, następne wywołaniebar
.for(y=0;y<Y;++y)for(x=0;x<X;++x)
często może stać sięfor(i=0;i<X*Y;++i)
zx
wyrazamii%X
iy
zastąpionei/X
.Wystarczy wspomnieć o oczywistym:
Podważ swój wybór algorytmu i wypróbuj coś zupełnie nowego.
Podczas gry w golfa (szczególnie trudniejsze problemy, które skutkują dłuższymi programami) zbyt często możesz trzymać się wybranej ścieżki, nie wypróbowując innych podstawowych opcji. Oczywiście możesz zagrać w mikro golfa na raz lub kilka linii na raz lub część ogólnego pomysłu, ale często nie próbujesz zupełnie innego rozwiązania.
Było to szczególnie widoczne w Uderzeniu 495 (Kaprekar), gdzie odbieganie od faktycznego algorytmu i szukanie wzorców, które można zastosować, aby uzyskać ten sam wynik, było krótsze w wielu językach (tylko nie J).
Minusem jest to, że prawdopodobnie rozwiązujesz to samo pół tuzina razy. Ale działa we wszystkich językach oprócz HQ9 + (gdzie znalezienie innego sposobu na wyświetlenie Hello World byłoby nieco daremne).
źródło
Użyj rozwoju opartego na testach
Jeśli kod musi obsługiwać różne dane wejściowe, napisz kompleksowe testy i bardzo szybko uruchom je wszystkie. Pozwala to wypróbować ryzykowne transformacje krok po kroku. Gra w golfa staje się wtedy jak refaktoryzacja z przewrotną intencją.
źródło
Spróbuj zmniejszyć logiczne instrukcje
Na przykład, jeśli
A
iB
są wartościami logicznymi, a Twój język traktuje wartości logiczne w pewnym stopniuA and (not B)
iA>B
są one równoważne. Na przykład w Pythoniejest taki sam jak:
źródło
B>A or foo()
byłoby jeszcze krótszym sposobem na wyrażenie tego, skorzystaj z leniwej oceny wyrażeń boolowskich, aby upewnić się, że oblicza rzeczy tylko wtedy, gdy jest to konieczne.B>A or foo
ocenia,foo
czyB==A
nie tego chcemy. (Racja?)Zainicjuj zmienne przy użyciu wartości, które już masz.
Zamiast tego
x=1
spróbuj poszukać czegoś, co już jest równe 1.Na przykład wartość zwracana przez funkcję:
printf("..");x=0;
->x=!printf("..");
. Najłatwiej jest z 0, ponieważ zawsze możesz zanegować lub gdy wszystko, czego potrzebujesz, to właściwa wartość prawdy (i nie przejmuj się, czy jest to 1 czy 19).źródło
Użyj unary
~
dlax+1
ix-1
Ta sztuczka dotyczy języków, w których występuje jednoargumentowy operator negacji bitowej
~
i jeden zwykły operator negacji-
.Jeśli Twój program przypadkowo zawiera wyrażenie
-x-1
, możesz je zastąpić,~x
aby zapisać bajty. Nie zdarza się to zbyt często, ale uważaj, co się stanie, jeśli negujemy (-
) oba wyrażenia:x+1
równa się-~x
! Podobniex-1
jest równy~-x
. (Zastanów się, w którą stronę wskazuje tylda: prawa jest+
, lewa jest-
.)Jest to przydatne, ponieważ we wszystkich językach, o których myślę, że mają te operatory, mają wyższy priorytet niż większość operatorów. Pozwala to zaoszczędzić na nawiasach. Zobacz, jak zapisujemy tutaj cztery bajty:
źródło
Ściśnij białe znaki
Poznaj zasady dotyczące białych znaków w swoim języku. Niektóre znaki interpunkcyjne lub inne znaki mogą nie wymagać otaczających białych znaków. Rozważ tę funkcję powłoki Bourne'a :
W powłoce Bourne'a
();
są metaznakami i nie potrzebują otaczających białych znaków. Są{}
to jednak słowa i wymagają spacji, chyba że znajdują się obok metaznaków. Możemy zagrać w golfa 4 pola obok();
, ale musimy zachować przestrzeń pomiędzy{
iecho
.W Common Lisp i PicoLisp ,
()
są metaznakami. Rozważ ten kod, aby znaleźć średnią dwóch liczb:Możemy zagrać w golfa na 2 pola.
Niektóre języki mają dziwne i subtelne reguły dotyczące białych znaków. Rozważ ten program Ruby, który wypisuje sumę i iloczyn linii liczb całkowitych.
Każdy
&
potrzebuje miejsca przed sobą. W Rubyi=$F.map &:to_i
oznacza,i=$F.map(&:to_i)
gdzie&
przekazuje parametr bloku. Alei=$F.map&:to_i
oznacza,i=$F.map.&(:to_i)
gdzie&
jest operator binarny.Ta dziwność zdarza się w językach takich jak Perl czy Ruby, które używają niejednoznacznych znaków interpunkcyjnych. W razie wątpliwości użyj REPL lub napisz krótkie programy, aby przetestować reguły białych znaków.
źródło
przypisuj funkcjom nowe nazwy, jeśli są używane wielokrotnie
źródło
x
.Nazwy zmiennych jednoliterowych
Masz ich 52; użyj ich wszystkich! Nie bój się wypróbować różnych metod i porównać długości. Zna język i konkretne dostępne skróty / funkcje biblioteczne.
źródło
$
i_
mogą być używane jako identyfikatory.@
jest poprawną nazwą zmiennej w T-SQL, użyj jej zamiast@a
.Użyj operatora warunkowego.
Operator warunkowy
jest bardziej korzystne, charakter mądry, niż IF oświadczenie .
można zapisać jako
źródło
a&&b||c
Zamiast tego można używać języków, które nie mają trójki . Nieco dłużej, ale wciąż krócej niżif
.Iff
, choć jest to funkcja, więc podlega ocenie wszystkich argumentów.if(a ? b : c)
a&&b||c
może powrócić,c
gdya
jest prawdą, iffb
jest fałszem, trochęNapisz objaśnienie swojego kodu
Napisanie wyjaśnienia zmusza cię do dokładnego spojrzenia na każdą część kodu i do wyrażenia swoich myśli i wyborów przy pisaniu określonego fragmentu. W ten sposób może się okazać, że możliwe są różne podejścia, które mogą zaoszczędzić niektóre bajty, lub że podświadomie przyjęliście założenia, które niekoniecznie się utrzymują.
Ta wskazówka jest podobna do Pytanie o wybór algorytmu i wypróbuj coś zupełnie nowego ; odkryłem jednak, że krok polegający na spisaniu, w jaki sposób ma działać każda część, jest czasem kluczowy dla uświadomienia sobie alternatyw.
Jako bonus, odpowiedzi zawierające wyjaśnienia są bardziej interesujące dla innych użytkowników i dlatego są bardziej prawdopodobne, że zostaną ocenione.
źródło
Sprawdź dwukrotnie liczbę swoich postaci
Brzmi jak oczywisty, ale uważając, możesz być w stanie „uratować” kilka postaci, nie robiąc nic!
Jeśli używasz systemu Windows, możesz wprowadzać dane
\r\n
zamiast po prostu\r
lub\n
po naciśnięciu klawisza Return - dodając dodatkowy bajt na wiersz! Przekręć znaki kontrolne, aby podwójnie sprawdzić, czy tego nie robisz.W Notepad ++ można przekonwertować wszystkie
\r\n
zakończenia linii,\r
przechodząc doEdit > EOL Conversion > UNIX/OSX Format
.Upewnij się także, że nie dołączasz żadnych białych znaków do liczby postaci! Przesuw wiersza w dolnej linii kodu również nie ma znaczenia, więc nie trzeba go też liczyć.
źródło
Przeczytaj uważnie pytanie
Gra w golfa kodowego polega zarówno na zrozumieniu pytania (co jest zadawane, a czego nie zadawane, nawet jeśli byłoby to sugerowane w innych ustawieniach), jak na tworzeniu kodu, który (może) zaspokoi tylko to, o co pytamy.
Wszelkie dane wejściowe inne niż jawnie wymagane nie muszą być przetwarzane. Jeśli istnieją pewne przypadki testowe i nie ma ogólnych wymagań, kod może działać tylko w tych przypadkach. Itp.
źródło
Użyj operacji bitowych do sprawdzania liczb od 0 do dowolnych 2 n -1
Może to być trochę ostry futerał, ale czasami może się przydać. Opiera się na fakcie, że wszystkie liczby, których dotyczy m = 2 n -1, mają skrajnie prawe n bitów ustawione na 1.
Tak więc 7 10 == 00000111 2 , 15 10 == 00001111 2 , 31 10 == 00011111 2 i tak dalej.
Sztuką jest
x&~m
. Zwróci wartość true, gdy niex
jest pomiędzy 0 a (włącznie), a false w przeciwnym razie. Zapisuje 6 bajtów od następnego najkrótszego równoważnego wyrażenia :, ale oczywiście działa tylko wtedy, gdy spełnia 2 n -1.m
x>=0&&x<=m
m
źródło
Ponownie użyj parametrów funkcji zamiast nowych zmiennych
źródło
main(i){...
masz teraz zmienną o wartości 1 bez konieczności wykonywać dowolne zadania. 2 znaki tam zapisane.Większa / mniejsza niż, aby zapisać cyfrę:
Pamiętaj tylko, aby zamienić kod z
if
naelse
i zrobią dokładnie to samo (lub zmienią boki nierówności)!Uwaga: można to zastosować przy dowolnej sile 10 i ich negatywach:
...-100, -10, 10, 100...
(link źródłowy)
źródło
if(n>99999)
vsif(n<1e5)
Użyj> i <zamiast> = i <=
Podczas sprawdzania z zakodowanymi liczbami całkowitymi wartości, użyj
>
oraz<
zamiast>=
i<=
gdzie to możliwe. Na przykład za pomocąJest o 2 bajty krótszy niż użycie
źródło
<1
zamiast kontroli==0
zerowej (lub>0
zamiast!=0
kontroli lustrzanej).x
byciu liczbą całkowitą?Unikaj przedwczesnych przerw w pętli
Jeśli biegnie się przez pętlę, aby sprawdzić 1 lub więcej wystąpień kontroli boolowskiej, może to sprawić, że wydajniejszy program może wyjść z pętli na pierwszej prawdziwej wartości. Jednak usunięcie przerwy i zapętlenie wszystkich iteracji pozwala na skrócenie kodu.
źródło
if
oświadczenie daleko w tych przypadkach:m|=i>=100
. (I można również uprościći>=100
, abyi>99
w tym przypadku, ale nie jest to bardzo istotne tutaj)użyj
-
zamiast!=
dla porównań numerycznych:
Jeśli a jest równe b,
a-b
powstaje0
, co jest fałszem. Wszystko inne niż0
jest prawdą; więcjeśli jest używany w kontekście logicznym,
a-b
<=>a!=b
Jeśli używasz go razem
if/else
z operatorem trójskładnikowym, może to również zaoszczędzić jeden bajt dla równości:a==b?c:d
<=>a-b?d:c
źródło
Rozdzielone ciągi dla długich tablic
Większość języków ma sposób na podzielenie łańcucha na tablicę łańcuchów wokół jakiegoś tokena. Będzie to nieuchronnie krótsze niż literał tablicowy, gdy długość osiągnie próg zależny od języka, ponieważ dodatkowy narzut na łańcuch będzie jedną kopią tokena o jednym znaku, a nie (przynajmniej) dwoma ogranicznikami łańcucha.
Np. W GolfScript
staje się
W niektórych językach próg jest tak niski jak jeden ciąg. Np. W Javie
staje się
źródło
%w{Foo Bar Baz Quux}
.qw(Foo Bar Baz Quux)
staje się listą ciągów znaków.Zrozum, co zrobili inni ludzie
Oprócz zabawy, gdy badasz kod innych osób, możesz czasem odkryć dobry algorytm, o którym nie pomyślałeś, lub sztuczkę (czasem oczywistą), którą przeoczysz.
Czasami istnieje odpowiedź, którą można przetłumaczyć na inny język i skorzystać z zalet tego drugiego języka.
źródło
znać swoje pierwszeństwo operatora
Ilekroć połączysz kilka wyrażeń, sprawdź tabelę priorytetów operatora dla swojego języka, aby zobaczyć, czy możesz zmienić kolejność rzeczy, aby zapisać nawiasy.
Przykłady:
(a&b)&&c
nie wymagają nawiasów:a&b&&c
tak jak(a*b)+c
nie.a+(b<<c)
można przepisać jakoa+b*2**c
.To nie oszczędza niczego dla tego przykładu, ale będzie, jeśli
c
jest to mała literałowa liczba całkowita (<14).a<b&&c<d
za<b&c<d
(chyba trzeba krótką ocenę obwodu)źródło
Krótsze pętle
Jeśli masz
X
instrukcje{
wewnątrz}
pętli for, możesz przenosićX-1
instrukcje(
wewnątrz)
pętli for po drugim średniku,for(blah;blah;HERE)
aby zapisać 3 bajty. (rozdziel instrukcje za pomocą przecinka,
)Zamiast
możesz przenieść jedną z instrukcji do
(
nawiasów klamrowych for-loop,)
a drugą pominąći zapisz 3 bajty (zapisałeś 1 bajt więcej dzięki @ETHProductions)
Mówiąc prościej,
zamiast
przesuń wyciągi, żeby tak się skończyło
i zapisz 3 bajty
źródło
for
to ostatnie zdanie,;
staje się opcjonalneUżyj unary
~
dlaa-b-1
ia+b+1
Oprócz sugestii @Lynn dotyczących
x+1
→-~x
; ix-1
→~-x
możesz także grać w golfaa-b-1
ia+b+1
.Może to wyglądać na wskazówkę, której nie będziesz używać tak często, tak jakby używanie
~x
zamiast-x-1
nie zdarzało się często, ale użyłem jej wystarczająco dużo razy, aby uznać ją za przydatną wskazówkę. Zwłaszcza w przypadku indeksowania tablic w niektórych przypadkach możesz użyć ich powyżej.źródło
Kompresuj i / lub smugi
Prosta sztuczka, którą wymyśliłem, próbując wycisnąć długą serię warunków połączonych przez ands (lub ors, w tym przypadku po prostu zamień „all” na „any”).
Na przykład:
Staje się
źródło
all(array-of-Booleans)
wbudowane?[a>0,a<10,a+b==4,a+3<1].all?
if 10>a>0 and a+b==4>1>a+3:
Polegaj na kompilatorze, aby zapewnić wymaganą wydajność.
Pamiętaj, które optymalizacje są gwarantowane przez kompilator i na jakich poziomach optymalizacji, i używaj ich swobodnie. A nawet jeśli wydajność nie jest
problememwymóg, nadal można przetestować z optymalizacji sprawie, i to tylko dlatego, że jeden znak zniżka kod jest wciąż technicznie poprawny bez flagi kompilatora.Rozważ następującą funkcję Haskella, aby obliczyć 2 ^ n (ignorując fakt, że Haskell ma już wbudowany operator potęgowania lub trzy) (23 znaki):
Problem w tym, że jest strasznie powolny, działa w wykładniczym czasie. Może to spowodować, że Twój kod będzie niestabilny lub nie spełnią żadnych ograniczeń wydajności podanych w pytaniu. Możesz skusić się na użycie zmiennej tymczasowej lub bezpośrednio wywołanej literału funkcji, aby uniknąć powtarzających się wywołań funkcji (25 znaków):
Ale kompilator może już to zrobić, wystarczy ustawić
-O
jako flagę kompilatora! Zamiast wydawać kilka dodatkowych znaków na witrynę, aby ręcznie wyeliminować typowe podwyrażenia, po prostu powiedz kompilatorowi, aby wykonał podstawowe optymalizacje dla ogólnej liczby jednego lub dwóch znaków w całym programie.źródło
p(x-1)*2
?Może nieco oczywiste, ale ...
Skorzystaj z wartości zwracanych przez operatora
Pamiętaj, że operator przypisania zwraca wartość!
Na przykład, jeśli chcesz dodać y do x, a następnie sprawdzić, czy x jest większe od czegoś, możesz to zrobić
zamiast
A może po przycięciu chcesz znaleźć długość sznurka:
Zamiast
źródło
a = (b=c)+1;
ustawiab
nac
, a następnie ustawiaa
nab+1
.a=1+b=c
. Możesz dodać PHP i JavaScript do swojej listy.=
operatorowi wyższy priorytet po lewej niż po prawej stronie, więc1+x=2
jest ważny i ocenia na3
Wykorzystaj wersję językową / kompilator / dziwactwa środowiskowe / nowe funkcje
Jest to szczególnie przydatne w przypadku poliglotów , ale można je zastosować do innych wyzwań. Czasami błąd kompilatora może odejść od bajtu, błąd implementacji może pozwolić Ci zaoszczędzić kilka znaków lub naprawdę najnowocześniejsza funkcja może poprawić twój wynik.
źródło
Połącz wiele / zagnieżdżonych, jeśli kontrole za pomocą i / lub, jeśli to możliwe.
to znaczy:
zamiast:
źródło
&
, `|), aby usunąć więcej znaków.&
zamiast&&
usuwać 1 znak w niektórych przypadkach zaburza pierwszeństwo operatora i będziesz musiał umieścić nawiasy, aby działało. Użyj go mądrze.Znajdź lepsze sposoby inicjalizacji zmiennych
Kilka innych odpowiedzi już prawie o tym wspomniało, ale w wielu językach (ściśle wpisanych?) Inicjowanie
x
jako pusty ciąg znaków jest krótsze :lub
x
jako pusta runa (char) jak:niż
i
Korzystanie z istniejących wartości jest oczywiście preferowane, ale nie takie łatwe.
źródło