सिक्के के टॉस के रूप में कई सिर के आधे होने की संभावना की गणना करें।
पुलिस में प्रवेश (कोनोर ओ ब्रायन द्वारा पोस्ट): /codegolf//a/100521/8927
मूल प्रश्न: सिक्का टॉस के रूप में कई सिर के रूप में आधा होने की संभावना की गणना करें।
पोस्ट किए गए समाधान में एक जोड़े को लागू करने की तकनीक थी, जिसके बाद एक ही ऑबफ्यूजन तकनीक की कई परतें थीं। एक बार पहले कुछ ट्रिक्स के बाद, यह वास्तविक कार्य निकालने के लिए एक सरल (यदि थकाऊ!) कार्य बन गया:
nCr(a,b) = a! / ((a-b)! * b!)
result = nCr(x, x/2) / 2^x
कुछ समय के लिए महसूस कर रहा था कि मैं क्या देख रहा था (थोड़ी देर के लिए मुझे किसी चीज़ पर शक करना था)।
चूंकि कॉनर ओ'ब्रायन ने अपने कोड के गहन विवरण को चुनौती दी थी, यहां अधिक दिलचस्प बिट्स का एक प्रकार है:
यह कुछ अंतर्निहित फ़ंक्शन कॉलों को बाधित करने से शुरू होता है। यह फ़ंक्शन नामों को आधार -32 एन्कोडिंग द्वारा प्राप्त किया जाता है, फिर उन्हें एक एकल वर्ण के नए वैश्विक-नामस्थानों को असाइन किया जाता है। केवल 'एटोब' का उपयोग वास्तव में किया जाता है; अन्य 2 सिर्फ लाल-झुंड हैं (eval के रूप में वही शॉर्टहैंड लेता है, केवल ओवरराइड किया जाता है, और btoa बस उपयोग नहीं किया जाता है)।
_=this;
[
490837, // eval -> U="undefined" -> u(x) = eval(x) (but overwritten below), y = eval
358155, // atob -> U="function (M,..." -> u(x) = atob(x)
390922 // btoa -> U="function (M,..." -> n(x) = btoa(x), U[10] = 'M'
].map(
y=function(M,i){
return _[(U=y+"")[i]] = _[M.toString(2<<2<<2)]
}
);
आगे कोड छिपाने के लिए तुच्छ स्ट्रिंग मिक्स-अप के कुछ जोड़े हैं। ये आसानी से उलट जाते हैं:
u(["","GQ9ZygiYTwyPzE6YSpk","C0tYSki","SkoYSkvZChhLWIpL2QoYikg"].join("K"))
// becomes
'(d=g("a<2?1:a*d(--a)"))(a)/d(a-b)/d(b) '
u("KScpKWIsYShFLCliLGEoQyhEJyhnLGM9RSxiPUQsYT1D").split("").reverse().join("")
// becomes
"C=a,D=b,E=c,g('D(C(a,b),E(a,b))')"
ऑबफसकेशन का थोक g
फ़ंक्शन का उपयोग है , जो बस नए कार्यों को परिभाषित करता है। यह पुनरावर्ती रूप से लागू किया जाता है, नए कार्यों को वापस करने वाले कार्यों के लिए, या मापदंडों के रूप में कार्यों की आवश्यकता होती है, लेकिन अंततः सही तरीके से सरल होता है। इससे बाहर आने का सबसे दिलचस्प कार्य है:
function e(a,b){ // a! / ((a-b)! * b!) = nCr
d=function(a){return a<2?1:a*d(--a)} // Factorial
return d(a)/d(a-b)/d(b)
}
इस लाइन के साथ एक अंतिम ट्रिक भी है:
U[10]+[![]+[]][+[]][++[+[]][+[]]]+[!+[]+[]][+[]][+[]]+17..toString(2<<2<<2)
// U = "function (M,i"..., so U[10] = 'M'. The rest just evaluates to "ath", so this just reads "Math"
यद्यपि अगला बिट ".pow (T, a)" है, इसलिए यह हमेशा बहुत संभव था कि इसे "गणित" होना चाहिए!
विस्तार कार्यों के मार्ग के साथ मैंने जो कदम उठाए, वे थे:
// Minimal substitutions:
function g(s){return Function("a","b","c","return "+s)};
function e(a,b,c){return (d=g("a<2?1:a*d(--a)"))(a)/d(a-b)/d(b)}
function h(a,b,c){return A=a,B=b,g('A(a,B(a))')}
function j(a,b,c){return a/b}
function L(a,b,c){return Z=a,Y=b,g('Z(a,Y)')}
k=L(j,T=2);
function F(a,b,c){return C=a,D=b,E=c,g('D(C(a,b),E(a,b))')}
RESULT=F(
h(e,k),
j,
function(a,b,c){return _['Math'].pow(T,a)}
);
// First pass
function e(a,b){
d=function(a){return a<2?1:a*d(--a)}
return d(a)/d(a-b)/d(b)
}
function h(a,b){
A=a
B=b
return function(a){
return A(a,B(a))
}
}
function j(a,b){ // ratio function
return a/b
}
function L(a,b){ // binding function (binds param b)
Z=a
Y=b
return function(a){
return Z(a,Y)
}
}
T=2; // Number of states the coin can take
k=L(j,T); // function to calculate number of heads required for fairness
function F(a,b,c){
C=a
D=b
E=c
return function(a,b,c){return D(C(a,b),E(a,b))}
}
RESULT=F(
h(e,k),
j,
function(a){return Math.pow(T,a)}
);
// Second pass
function e(a,b){...}
function k(a){
return a/2
}
function F(a,b,c){
C=a
D=b
E=c
return function(a,b,c){return D(C(a,b),E(a,b))}
}
RESULT=F(
function(a){
return e(a,k(a))
},
function(a,b){
return a/b
},
function(a){return Math.pow(2,a)}
);
// Third pass
function e(a,b) {...}
C=function(a){ // nCr(x,x/2) function
return e(a,a/2)
}
D=function(a,b){ // ratio function
return a/b
}
E=function(a){return Math.pow(2,a)} // 2^x function
RESULT=function(a,b,c){
return D(C(a,b),E(a,b))
}
फ़ंक्शन नेस्टिंग की संरचना उपयोगिता के आसपास आधारित है; बाहरी सबसे "डी" / "जे" फ़ंक्शन एक अनुपात की गणना करता है, फिर आंतरिक "सी" / "एच" और "ई" (इनलाइन) फ़ंक्शन आवश्यक सिक्का फ्लिप गणना की गणना करता है। तीसरे पास में हटाए गए "एफ" फ़ंक्शन को एक साथ एक प्रयोग करने योग्य पूरे में जोड़ने के लिए जिम्मेदार है। इसी तरह "के" फ़ंक्शन उन प्रमुखों की संख्या को चुनने के लिए जिम्मेदार है जिन्हें देखने की आवश्यकता है; एक कार्य जिसे यह पैरामीटर बाइंडिंग फ़ंक्शन "L" के माध्यम से "D" / "j" अनुपात फ़ंक्शन के लिए दर्शाता है; पैरामीटर b
को ठीक करने के लिए यहां उपयोग किया जाता हैT
(यहाँ हमेशा 2, राज्यों की संख्या का सिक्का ले जा सकते हैं किया जा रहा है)।
अंत में, हम प्राप्त करते हैं:
function e(a,b){ // a! / ((a-b)! * b!)
d=function(a){return a<2?1:a*d(--a)} // Factorial
return d(a)/d(a-b)/d(b)
}
RESULT=function(a){
return e(a, a/2) / Math.pow(2,a)
}