जावा 8 लैम्ब्डा, 1506 1002 972 942 अक्षर
मैं इस चुनौती को हराना चाहता था, क्योंकि यह बहुत दिलचस्प है। परिणाम (बहुत गोल्फ नहीं) यहाँ देखा जा सकता है:
import java.util.*;f->{Set<double[]>B=new HashSet(),r,n;double a,M,m,P=Math.PI*2,z=.5;int x=0,y,v=0,i,j,c[],p,q,l=g.length;for(;x<l;x++)for(y=0;y<g[x].length;y++)if(g[x][y]>63)for(;;){c=new int[]{-1};M=2e31-1;for(i=0;i<l;i++)for(j=0;j<g[i].length;j++)if(g[i][j]==42)if((m=(p=x-i)*p+(q=y-j)*q)<M){M=m;c=new int[]{i,j};}if(c[0]<0)break;g[c[0]][c[1]]=0;double[]A={(a=Math.atan2((c[1]-=y)-z,(c[0]-=x)-z))<0?a+P:a,(a=Math.atan2(c[1]+z,c[0]-z))<0?a+P:a,(a=Math.atan2(c[1]+z,c[0]+z))<0?a+P:a,(a=Math.atan2(c[1]-z,c[0]+z))<0?a+P:a};r=new HashSet();M=-P;m=P;for(double d:A){M=d>M?d:M;m=d<m?d:m;}r.add(new double[]{m,M});for(double[]t:B){n=new HashSet();for(double[]h:r)for(double[]u:t[0]<h[0]?t[1]<h[0]?new double[][]{h}:t[1]<h[1]?new double[][]{{t[1],h[1]}}:new double[0][]:t[0]>h[1]?new double[][]{h}:t[1]>h[1]?new double[][]{{h[0],t[0]}}:new double[][]{{h[0],t[0]},{t[1],h[1]}})if(u[0]<u[1])n.add(u);r=n;}B.addAll(r);if(!r.isEmpty())v++;}return v;}
बेशक यह भी ungolfed संस्करण में मौजूद है:
import java.util.*;
public class AngleCheck {
static int getViewableBuildingsC(char[][] grid) {
Set<double[]> blocked = new HashSet(), ranges, newRanges;
double angle, max, min, PI2 = Math.PI * 2, half = 0.5;
int x = 0, y, viewable = 0, i, j, building[], dX, dY, length = grid.length;
for (; x < length; x++) {
for (y = 0; y < grid[x].length; y++) {
if (grid[x][y] > 63) {
for (;;) {
building = new int[]{-1};
max = 2e31-1;
for (i = 0; i < length; i++) {
for (j = 0; j < grid[i].length; j++) {
if (grid[i][j] == 42) {
if ((min = (dX = x - i) * dX + (dY = y - j) * dY) < max) {
max = min;
building = new int[]{i, j};
}
}
}
}
if (building[0] < 0)
break;
grid[building[0]][building[1]] = 0;
double[] angles = {
(angle = Math.atan2((building[1] -= y) - half, (building[0] -= x) - half)) < 0 ? angle + PI2 : angle,
(angle = Math.atan2(building[1] + half, building[0] - half)) < 0 ? angle + PI2 : angle,
(angle = Math.atan2(building[1] + half, building[0] + half)) < 0 ? angle + PI2 : angle,
(angle = Math.atan2(building[1] - half, building[0] + half)) < 0 ? angle + PI2 : angle};
ranges = new HashSet();
max = -PI2;
min = PI2;
for (double d : angles) {
max = d > max ? d : max;
min = d < min ? d : min;
}
ranges.add(new double[]{min, max});
for (double[] reference : blocked) {
newRanges = new HashSet();
for (double[] currentRange : ranges) {
for (double[] subRange : reference[0] < currentRange[0] ?
reference[1] < currentRange[0] ?
// whole range after referencerange
new double[][]{currentRange}
:
reference[1] < currentRange[1] ?
// lower bound inside referencerange, but upper bound outside
new double[][]{{reference[1], currentRange[1]}}
:
// whole range inside referencerange -> nothing free
new double[0][]
:
// greater or equal lower bound
reference[0] > currentRange[1] ?
// whole range before referencerange
new double[][]{currentRange}
:
// ranges overlap
reference[1] > currentRange[1] ?
// range starts before and ends in reference range
new double[][]{{currentRange[0], reference[0]}}
:
// referencerange is in the range -> two free parts, one before, one after this
new double[][]{{currentRange[0], reference[0]}, {reference[1], currentRange[1]}}) {
if (subRange[0] < subRange[1])
newRanges.add(subRange);
}
}
ranges = newRanges;
}
blocked.addAll(ranges);
if (!ranges.isEmpty()) {
viewable++;
}
}
}
}
}
return viewable;
}
}
तो यह बहुत मुश्किल लग रहा है, लेकिन यह जिस तरह से सोच सकता है उससे ज्यादा आसान है। मेरा पहला विचार कुछ चौराहे एल्गोरिदम का उपयोग करके यह जांचने के लिए था कि क्या मेरी स्थिति से इमारत तक कोई रेखा बिना किसी चौराहे के बनाई जा सकती है। ऐसा करने के लिए मैंने कोहेन-सदरलैंड एल्गोरिथ्म का उपयोग करने और इमारत के सभी चारों कोनों तक लाइनें खींचने का फैसला किया। इसने पहले परीक्षणों के लिए बहुत अच्छा काम किया, लेकिन अंतिम असफल रहा। मुझे जल्द ही पता चला, कि यह एक ऐसा मामला है जहाँ आप कोनों को नहीं बल्कि एक किनारे का हिस्सा देख सकते हैं। तो मैंने सोचा कि कुछ प्रकार की किरण के बारे में @Blue ने ऐसा किया है। मैंने उस चुनौती को दूर रखा, क्योंकि मुझे कुछ प्रगति नहीं मिली। फिर मैंने ब्लू का उत्तर देखा और मेरे दिमाग में निम्नलिखित सरल विचार आया: प्रत्येक इमारत कुछ कोण को अवरुद्ध करती है जिसमें कुछ और नहीं देखा जा सकता है। मुझे सिर्फ इस बात पर नज़र रखने की ज़रूरत है कि अन्य इमारतों द्वारा क्या देखा जा सकता है और क्या पहले से ही छिपा हुआ है। बस!
एल्गोरिथ्म निम्नानुसार काम करता है: यह व्यक्ति को सबसे छोटी दूरी के साथ इमारत को निर्धारित करता है। तब हम व्यक्ति से भवन के कोने तक खींची गई चार पंक्तियों की कल्पना करते हैं। इनमें से दो का अत्यधिक मूल्य है: न्यूनतम और अधिकतम कोण जिसमें इमारत को देखा जा सकता है। हम उन्हें एक सीमा के रूप में लेते हैं और उनकी तुलना अन्य इमारतों से करते हैं जिनके बारे में हम जानते हैं कि उन्हें देखा जा सकता है (शुरुआत में कोई नहीं)। सीमाएँ ओवरलैप हो सकती हैं, एक दूसरे को शामिल कर सकती हैं या बिल्कुल भी नहीं छू सकती हैं। मैं पर्वतमाला की तुलना करता हूं और भवन की कुछ नई श्रेणियां प्राप्त करता हूं जो देखने योग्य भवनों द्वारा छिपी नहीं हैं। यदि भवन के साथ तुलना करने के बाद कुछ शेष है, तो भवन भी देखने योग्य है। हम तुलना करने के लिए शेष कोण श्रेणी को अगली लंबी दूरी के साथ अगली इमारत के साथ शुरू करने के लिए श्रेणियों की सूची में जोड़ते हैं।
कभी-कभी सीमाएं इस तरह से ओवरलैप हो सकती हैं कि मैं 0 डिग्री की सीमा के साथ समाप्त हो जाए। इन श्रेणियों को गलत तरीके से एक इमारत जोड़ने के लिए फ़िल्टर किया जाएगा जो देखने योग्य भी नहीं है।
मुझे आशा है कि किसी ने इस स्पष्टीकरण को समझा :)
मुझे पता है कि यह कोड बहुत अधिक नहीं है, मैं इस asap करूँगा।
यह वास्तव में चुनौतीपूर्ण कार्य था। आपने सोचा था कि आपको एक समाधान मिला है जो काम करता है लेकिन इसके बजाय आप अभी भी दूर हैं। मुझे लगता है कि यह समाधान बहुत अच्छा काम करता है। यह बहुत तेज़ नहीं है, लेकिन कम से कम यह काम करता है;) उस पहेली के लिए धन्यवाद!
अपडेट करें
मैंने पूरी चीज़ को एक ही फंक्शन में नीचे गिराने का समय पाया, जिसे इस प्रकार एक मेमने में बदल दिया जा सकता है। सभी कार्यों को केवल एक बार बुलाया गया था और इस प्रकार एक विधि में रखा जा सकता है। मैं सूचियों से लेकर सेट तक स्विच करता हूं क्योंकि यह कुछ अतिरिक्त पात्रों को बचाता है। घोषणाओं को एक साथ रखा गया है। तुलनाओं को एक साथ रखा गया है और पात्रों को वहां एएससीआई मूल्य से बदल दिया गया है। तुलना करने वाली सीमा को कई ternaries के रूप में व्यक्त किया जा सकता है। यहाँ पर कुछ ट्रिक्स दिए गए हैं ताकि डबल.NEGATIVE_INFINITY जैसे लंबे एक्सप्रेशन को रोका जा सके। जहां संभव इनलाइन असेस्मेंट किए जाते हैं। थोड़ा और अधिक बचाने के लिए मैंने कोणों को डिग्रियों की तुलना में रेडियों की तुलना करने से रोका। पूरे बदलाव ने 500 से अधिक पात्रों को बचाया, मुझे उम्मीद है कि यह सब 1000 से कम होगा;)
मैंने उन जेनेरिक को हटा दिया जहां संभव हो और एक तत्व एरे को बनाकर वापसी की तुलना को छोटा कर दिया और इसके बदले मान की जांच की। मैंने PI.2 और -PI2 के साथ Double.NEGATIVE_INFINITY को भी बदल दिया क्योंकि ये कोण के ऊपरी और निचले सीमा हैं। अब यह अंततः 1000 वर्णों से कम लंबा है!
मैंने कुछ वर्णों को सहेजने के लिए व्यक्तियों के स्थान और भवन की खोज के लिए छोरों को मिला दिया। दुर्भाग्य से हमें लूप से रिटर्न को स्थानांतरित करने की आवश्यकता है और अभी भी एक ब्रेक का उपयोग करें लेकिन इस बार लेबल के बिना। मैं विलय कर दिया maxऔर distanceSquaredऔर minऔर newDistanceSquaredके रूप में वे एक ही समय में आवश्यकता नहीं है। मैं बदल Integer.MAX_VALUEगया 2e31-1। इसके अलावा मैंने एक स्थिरांक बनाया half = 0.5जिसका उपयोग भवन के कोनों की गणना करने के लिए किया जाता है। यह गोल्फ वाले संस्करण में छोटा है। कुल मिलाकर हमने एक और 30 अक्षर बचाए!