Java 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;}
แน่นอนว่าสิ่งนี้มีอยู่ในเวอร์ชันที่ไม่ได้รับรางวัล:
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;
}
}
มันดูยากมาก แต่มันง่ายกว่าที่คิด ความคิดแรกของฉันคือการใช้อัลกอริทึมสี่แยกบางส่วนเพื่อตรวจสอบว่าสามารถใช้เส้นจากตำแหน่งของฉันไปยังสิ่งปลูกสร้างได้หรือไม่ เมื่อต้องการทำสิ่งนี้ฉันตัดสินใจที่จะใช้อัลกอริทึม Cohen-Sutherland และวาดเส้นไปยังมุมทั้งสี่ของอาคาร วิธีนี้ใช้ได้ผลดีสำหรับการทดสอบครั้งแรก แต่การทดสอบครั้งสุดท้ายล้มเหลว ในไม่ช้าฉันก็พบว่าเป็นกรณีที่คุณไม่สามารถมองเห็นมุม แต่เป็นส่วนหนึ่งของขอบ ดังนั้นฉันจึงคิดถึงการฉายรังสีแบบบางอย่างเช่น @Blue ฉันเอาความท้าทายนั้นออกไปเนื่องจากฉันไม่ได้รับความคืบหน้า จากนั้นฉันก็เห็นคำตอบของบลูและความคิดที่เรียบง่ายต่อไปนี้อยู่ในใจของฉัน: แต่ละหน่วยสร้างบล็อกบางมุมซึ่งไม่มีอะไรมองเห็นได้อีก ฉันแค่ต้องติดตามสิ่งที่สามารถมองเห็นได้และสิ่งที่ถูกซ่อนอยู่โดยอาคารอื่น ๆ แค่นั้นแหละ!
อัลกอริทึมทำงานดังนี้: มันกำหนดอาคารที่มีระยะทางน้อยที่สุดกับบุคคล จากนั้นเราจินตนาการถึงเส้นสี่เส้นที่ลากจากคนสู่มุมอาคาร สองสิ่งนี้มีค่ามาก: มุมต่ำสุดและสูงสุดที่สามารถมองเห็นอาคารได้ เราใช้มันเป็นระยะและเปรียบเทียบกับอาคารอื่น ๆ ที่เรารู้ว่าพวกเขาสามารถมองเห็นได้ (ไม่มีในตอนแรก) ช่วงอาจทับซ้อนกันรวมกันหรือไม่แตะเลย ฉันเปรียบเทียบช่วงและรับช่วงใหม่ของอาคารซึ่งไม่ได้ซ่อนอยู่ในอาคารที่ดูได้ หากมีสิ่งที่เหลืออยู่หลังจากการเปรียบเทียบกับอาคารที่อยู่ในสายตาอาคารนั้นก็สามารถดูได้เช่นกัน เราเพิ่มช่วงมุมที่เหลือลงในรายการช่วงเพื่อเปรียบเทียบและเริ่มต้นด้วยสิ่งปลูกสร้างถัดไปด้วยระยะทางที่ไกลขึ้น
บางครั้งช่วงอาจทับซ้อนกันในวิธีที่ฉันจบด้วยช่วงของ 0 องศา ช่วงเหล่านี้จะถูกกรองเพื่อไม่ให้เพิ่มสิ่งปลูกสร้างที่ไม่สามารถดูได้โดยไม่ตั้งใจ
ฉันหวังว่าบางคนเข้าใจคำอธิบายนี้ :)
ฉันรู้ว่ารหัสนี้ไม่ได้เล่นกอล์ฟมากฉันจะทำอย่างนี้โดยเร็ว
นั่นเป็นงานที่ท้าทายจริงๆ คุณคิดว่าคุณพบวิธีแก้ปัญหาที่ใช้ได้ผล แต่คุณกลับยังอยู่ห่างไกล ฉันคิดว่าวิธีนี้ใช้ได้ดีทีเดียว มันไม่เร็วมาก แต่อย่างน้อยก็ใช้งานได้) ขอขอบคุณสำหรับปริศนาตัวต่อ!
ปรับปรุง
ฉันพบว่าเวลาเล่นกอล์ฟสิ่งทั้งหมดลงในฟังก์ชั่นเดียวซึ่งสามารถกลายเป็นแลมบ์ดา ฟังก์ชั่นทั้งหมดถูกเรียกเพียงครั้งเดียวเท่านั้นและสามารถใส่เป็นวิธีการเดียว ฉันเปลี่ยนจากรายการเป็นการตั้งค่าเนื่องจากนี่จะช่วยเพิ่มตัวอักขระเพิ่มเติม ประกาศได้รับการรวบรวม การเปรียบเทียบถูกรวบรวมเข้าด้วยกันและอักขระถูกแทนที่ด้วยค่า ascii ช่วงการเปรียบเทียบสามารถแสดงได้หลายระดับ เทคนิคบางอย่างที่นี่และที่นั่นเพื่อป้องกันไม่ให้มีการแสดงออกที่ยาวนานเช่น DoubleNEGATIVE_INFINITY หากเป็นไปได้ให้ทำแบบอินไลน์ได้ เพื่อประหยัดอีกเล็กน้อยฉันเปลี่ยนจากการเปรียบเทียบมุมเป็นองศาเพื่อเปรียบเทียบเรเดียน การเปลี่ยนแปลงทั้งหมดได้รับการบันทึกไว้มากกว่า 500 ตัวอักษรฉันหวังว่าจะได้รับทั้งหมด 1,000 ตัว แต่;)
ฉันลบข้อมูลทั่วไปเมื่อเป็นไปได้และทำให้การเปรียบเทียบผลตอบแทนสั้นลงด้วยการสร้างอาร์เรย์องค์ประกอบหนึ่งและตรวจสอบค่าของมันแทน ฉันยังแทนที่ Double.NEGATIVE_INFINITY ด้วย PI2 และ -PI2 เนื่องจากนี่คือขอบเขตบนและล่างของมุม ตอนนี้มันยาวไม่เกิน 1,000 ตัวอักษร!
ฉันรวมลูปสำหรับค้นหาตำแหน่งบุคคลและตัววนซ้ำของอาคารเพื่อบันทึกอักขระบางตัว น่าเสียดายที่สิ่งนี้ต้องการให้เราย้ายการส่งคืนออกจากลูปและยังคงใช้ตัวแบ่ง แต่คราวนี้ไม่มีฉลาก ฉันรวมmax
และdistanceSquared
และmin
และnewDistanceSquared
ที่พวกเขาจะไม่จำเป็นต้องใช้ในเวลาเดียวกัน ผมเปลี่ยนไปInteger.MAX_VALUE
2e31-1
ฉันยังสร้างค่าคงhalf = 0.5
ที่ซึ่งใช้ในการคำนวณมุมของอาคาร นี่จะสั้นกว่าในเวอร์ชัน golfed โดยรวมแล้วเราบันทึกอีก 30 ตัวอักษร!