Golfscript - 12 karakter
{,1\{)*}/}:f
Golfscript - Factorial'ı adım adım tanıma
İşte golf senaryosunu öğrenmeye çalışanlar için bir şeyler. Önkoşul golfcript ile ilgili temel bir anlayış ve golfcript belgelerini okuma yeteneğidir.
Bu yüzden yeni araç golf senaryomuzu denemek istiyoruz . Basit bir şeyle başlamak her zaman iyidir, bu yüzden faktoring ile başlıyoruz. İşte basit bir emir sözde kodunu temel alan ilk deneme:
# 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
Boşluk nadiren golfscript'te kullanılır. Beyaz alandan kurtulmanın en kolay yolu farklı değişken isimleri kullanmaktır. Her belirteç değişken olarak kullanılabilir ( sözdizimi sayfasına bakın). Değişkenler gibi özel karakterler olarak Faydalı jetonlar kullanmak |
, &
, ?
kodda başka yerde kullanılan genel bir şey değil -. Bunlar her zaman tek karakter belirteçleri olarak ayrıştırılır. Buna karşılık, gibi değişkenler n
sonradan yığına bir sayı itmek için bir boşluk gerektirir. Sayılar temelde önceden başlatılmış değişkenlerdir.
Her zaman olduğu gibi, nihai sonucu etkilemeden değiştirebileceğimiz ifadeler olacak. Golfscript, her şey hariç doğru olarak değerlendirilir 0
, []
, ""
ve {}
(bkz bu ). Burada loop çıkış koşulunu basitçe değiştirebiliriz {n}
(ek bir süre döngü kurar ve n = 0 olduğunda sonlandırırız).
Herhangi bir dilde golf oynamak gibi, mevcut fonksiyonları bilmek de yardımcı olur. Neyse ki liste golfscript için çok kısa. Başka bir karakter kaydetmek 1-
için değişebiliriz (
. Şu anda kod şöyle gözüküyor: ( eğer istiyorsak, başlangıç 1
yerine |
bırakacak olursak , burada yerine kullanabilirdik .)
{:n;1:|;{n}{n|*:|;n(:n;}while|}:f
En kısa çözümleri elde etmek için yığını iyi kullanmak önemlidir (pratik uygulama uygulaması). Genel olarak, değerler yalnızca küçük bir kod segmentinde kullanılıyorsa, bunları değişkenlere depolamak gerekli olmayabilir. Çalışan ürün değişkenini kaldırarak ve sadece yığını kullanarak, oldukça fazla karakter kaydedebiliriz.
{:n;1{n}{n*n(:n;}while}:f
İşte düşünecek başka bir şey var. Değişkeni n
döngü gövdesinin sonundaki yığından kaldırıyoruz , ancak hemen sonra itiyoruz. Aslında, döngü başlamadan önce onu da yığından kaldırırız. Onun yerine yığını bırakmalıyız ve döngü koşulunu boş tutabiliriz.
{1\:n{}{n*n(:n}while}:f
Belki de değişkeni tamamen ortadan kaldırabiliriz. Bunu yapmak için, değişkeni her zaman yığında tutmamız gerekir. Bu, durum kontrolünün sonunda yığındaki değişkenin iki kopyasına ihtiyacımız olduğu anlamına gelir, böylece kontrolden sonra kaybetmemeliyiz. Bu 0
, döngü sona erdikten sonra yığında bir yedekli olacağımız anlamına gelir , ancak bu düzeltilmesi kolaydır.
Bu bizi optimal while
döngü çözümümüze yönlendirir!
{1\{.}{.@*\(}while;}:f
Şimdi hala bunu kısaltmak istiyoruz. Açık hedef, kelime olmalı while
. Belgelere bakıldığında, iki uygun seçenek vardır - açılmak ve yapmak . Alınacak farklı rota seçenekleriniz olduğunda, her ikisinin de faydalarını deneyin ve tartın. Açılmak 'hemen hemen bir döngü' olduğundan, bir tahmin olarak 5 karakteri while
4'e indireceğiz /
. Gelince do
, while
3 karakter kesiyoruz ve iki veya iki bloğu birleştiriyoruz, ki bu bir veya iki karakter daha kaydedebiliyor.
Aslında bir do
döngü kullanmanın büyük bir dezavantajı var . Koşul kontrolü, vücut bir kez yürütüldükten sonra yapıldığından, değeri 0
yanlış olacaktır, bu nedenle bir if ifadesine ihtiyacımız olabilir. Şimdi, açılma işleminin daha kısa olduğunu söyleyeyim (sonunda bazı çözümler sunulur do
). Devam et ve dene, elimizde olan kodun minimum bir değişikliğe ihtiyacı var.
{1\{}{.@*\(}/;}:f
Harika! Bizim çözümümüz artık çok kısa ve burada işimiz bitti değil mi? Hayır! Bu 17 karakter ve J 12 karakterden oluşuyor. Asla yenilgiyi kabul etme!
Şimdi düşünüyorsun ... özyinelemeyle
Özyinelemeyi kullanmak dallanma yapısını kullanmamız gerektiği anlamına gelir . Talihsiz, ancak faktoring özlü bir şekilde özyinelemeli olarak ifade edilebildiğinden, bu yinelemeye uygulanabilir bir alternatif gibi görünüyor.
# pseudocode: f(n){return n==0?n*f(n-1):1}
{:n{n.(f*}1if}:f # taking advantage of the tokeniser
Eh bu kolaydı - özyinelemeyi daha önce denemiş olsaydık, bir while
döngü kullanmaya bile bakmamış olabilirdik ! Yine de, sadece 16 karakterdeyiz.
Diziler
Diziler genellikle iki şekilde oluşturulur - [
ve ]
karakterlerini kullanarak veya ,
işlevini kullanarak. Yığının en üstünde bir tamsayı ile çalıştırılırsa ,
, bu uzunluktaki bir diziyi arr [i] = i ile döndürür.
Dizileri yinelemek için üç seçeneğimiz var:
{block}/
: ittir, engelle, ittir, engelle, ...
{block}%
: [push, block, push, block, ...] (bunun bazı nüansları vardır, örneğin ara değerler istiflerden önce yığından çıkarılır)
{block}*
: ittir, ittir, engelle, ittir, engelle, ...
Golfscript belgelerinin {+}*
bir dizinin içeriğini toplamak için kullanma örneği vardır . Bu {*}*
, bir dizinin ürününü almak için kullanabileceğimizi gösteriyor .
{,{*}*}:f
Ne yazık ki, o kadar basit değil. Tüm elemanlar birer birer kapalıdır ( [0 1 2]
yerine [1 2 3]
). {)}%
Bu sorunu düzeltmek için kullanabiliriz .
{,{)}%{*}*}:f
Pek iyi değil. Bu sıfırı doğru işlemez. Bunu düzeltmek için (n + 1)! / (N + 1) 'i hesaplayabiliriz, bunun maliyeti çok fazladır.
{).,{)}%{*}*\/}:f
Aynı zamanda n = 0'ı n = 1 ile aynı kovada işlemeyi deneyebiliriz. Bu, yapmak, denemek ve mümkün olan en kısa sürede çalışmak için son derece kısa bir gerçektir.
Pek iyi değil 7 karakter, sıralama edilir: [1\]$1=
. Bu sıralama tekniğinin bir sayıya sınırlar koymak gibi faydalı amaçları olduğunu unutmayın (örneğin, [[0 \ 100] $ 1 =)
İşte kazanan, sadece 3 karakterli:.! +
Artış ve çarpmayı aynı blokta yapmak istiyorsak, dizideki her eleman üzerinde yinelemeliyiz. Bir dizi oluşturmadığımızdan, bu {)*}/
bizi kullanmamız gerektiği anlamına gelir , bu da bizi faktoringin en kısa golf senaryo uygulamasına götürür! 12 karakter uzunluğunda, bu J ile bağlantılı!
{,1\{)*}/}:f
Bonus çözümler
if
Bir do
döngü için basit bir çözümle başlamak :
{.{1\{.@*\(.}do;}{)}if}:f
Bundan bir kaç tane daha alabiliriz. Biraz karışık, bu yüzden bu işlerin işe yarayacağına inanmalısın. Bunları anladığınızdan emin olun.
{1\.!!{{.@*\(.}do}*+}:f
{.!{1\{.@*\(.}do}or+}:f
{.{1\{.@*\(.}do}1if+}:f
Daha iyi bir alternatif, (n + 1)! / (N + 1) 'i hesaplamaktır, bu da bir if
yapıya olan ihtiyacı ortadan kaldırır .
{).1\{.@*\(.}do;\/}:f
Ancak buradaki en kısa do
çözüm, 0'dan 1'e eşlemek için birkaç karakter ve kendi başına başka her şeyi alır - bu nedenle dallara ihtiyacımız yoktur. Bu tür bir optimizasyonun kaçırılması son derece kolaydır.
{.!+1\{.@*\(.}do;}:f
İlgilenenler için, yukarıda belirtilen uzunluktaki birkaç özyinelemeli özyinelemeli çözüm burada verilmektedir:
{.!{.)f*0}or+}:f
{.{.)f*0}1if+}:f
{.{.(f*}{)}if}:f
* not: Aslında bu yazıda kod parçalarının çoğunu test etmedim, bu nedenle hata olup olmadığını bildirmekten çekinmeyin.