เมือง: Sightlines


18

ฉันอยู่ในตำแหน่ง(0, 0)ของเมืองสองมิติที่ไม่มีที่สิ้นสุดซึ่งแบ่งออกเป็นบล็อกที่มีศูนย์กลางอยู่ที่จุดขัดแตะแต่ละจุดอย่างสมบูรณ์ซึ่งบางส่วนมีอาคาร อาคารที่จุดหนึ่ง(x, y)รับทั้งจัตุรัสโดยมีมุมตรงข้ามที่(x-.5, y-.5)และ (x + .5, y + .5)รวมถึงชายแดนด้วย อาคารจะมองเห็นได้หากมีส่วนของเส้นบางส่วนจาก(0, 0)ถึงจุดหนึ่งในอาคารที่ไม่ตัดกับอาคารอื่น

ตัวอย่างเช่นฉัน (the @) สามารถดู 6 อาคาร ( *) ในเมืองต่อไปนี้:

  *
 *
*
*@
x**
 *  y

ฉันไม่สามารถเห็นอาคารที่มีเครื่องหมายxที่(-1, -1)เพราะถูกกีดขวางโดยทั้งสองอยู่ติดกับอาคาร หรือคนที่มีเครื่องหมายyที่(3, -2)เพราะมันบดบังด้วยขอบของ(1, -1)อาคาร

อินพุต

สตริงหลายบรรทัดหรือรายการของบรรทัดมีทางเลือกเสริมด้วยช่องว่างลงในสี่เหลี่ยมผืนผ้า มันจะมีเพียง:

  • หนึ่ง@(ตำแหน่งของฉัน)
  • ช่องว่าง
  • *ซึ่งเป็นตัวแทนของอาคาร

จะมีอาคารอย่างน้อยหนึ่งแห่งเสมอและดังนั้นจึงมีอาคารที่มองเห็นได้อย่างน้อยหนึ่งแห่ง

เอาท์พุต

จำนวนอาคารที่มองเห็นได้

กรณีทดสอบ

*@
1

* *******
 @     * 
7

*****
**@**
*****
4

   *
  **
@ **
2

*      *
 *    * 
@
4

@
 *
  ***
1

ขอขอบคุณที่ @Geobits สำหรับชื่อ



เกี่ยวกับกรณีทดสอบ 3 มันล้อมรอบด้วย 8 * แต่ผลลัพธ์คือ 4 แต่มุมเหล่านั้นดูเหมือนจะไม่ถูกบล็อกโดยอาคารอื่น มีกฎหรือไม่ที่จะไม่รวมมุมต่างๆ?
LukStorms

1
@ Lukstorms ลองนึกภาพดาวแต่ละดวงนั้นเป็นลูกบาศก์จริง ๆ แล้วเหมือนใน minecraft หากคุณกำลังยืนอยู่ตรงกลางคุณจะสามารถเห็น 4 ช่วงตึกเท่านั้น
บลู

คุณจะกรุณารอก่อนที่ฉันจะเข้าสู่สนามกอล์ฟของฉัน (เร็ว ๆ นี้) ก่อนที่จะตัดสินรางวัล? :)
Leif Willerts

คำตอบ:


4

Unity + C #, 589 ไบต์

นี่อาจเป็นภาษาที่เลวร้ายที่สุดในการทำรหัสกอล์ฟ (อ่าน: แย่กว่า Java) แต่ Unity มาพร้อมกับคุณสมบัติที่มีประโยชน์มากมายสำหรับความท้าทายนี้

แก้ไข: พลาดช่องว่างสองสามรายการส่งคืนความยาวของรายการไม่ใช่ตัวนับ

แข็งแรงเล่นกอล์ฟ:

using UnityEngine;using System.Collections;public class c:MonoBehaviour{public int h(string[]i){ArrayList k=new ArrayList();for(int y=0;y<i.Length;y++){char[]l=i[y].ToCharArray();int x=0;foreach(char c in l){if(c=='*'){GameObject b=GameObject.CreatePrimitive(PrimitiveType.Cube);b.transform.position=new Vector3(x,y);}if(c=='@')transform.position=new Vector3(x,y);x++;}}for(int n=0;n<3600;n++){RaycastHit h;Physics.Raycast(transform.position,Quaternion.Euler(0,0,n/10)*Vector3.up,out h);if(h.collider!=null){GameObject o=h.collider.gameObject;if(!k.Contains(o))k.Add(o);}}return k.Count;}}

Ungolfed:

using UnityEngine;
using System.Collections;

public class citiessightlines : MonoBehaviour {

    public ArrayList todelete;   // Anything concerning this array just has to do with cleanup of 
                                 //objects for testing, and doesn't contribute to the byte count.
    void Start()
    {
        todelete = new ArrayList();
    }
    public int calcSight(string[]input)
    {
        todelete = new ArrayList();
        int total = 0;
        ArrayList check = new ArrayList();
        for (int y=0;y < input.Length; y++)
        {
            char[] line = input[y].ToCharArray();
            for (int x = 0; x < line.Length; x++)
            {
                char c = line[x];
                if (c == '*')
                {
                    GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
                    cube.transform.position = new Vector3(x, y);
                    todelete.Add(cube);
                }
                if (c == '@')
                {
                    transform.position = new Vector3(x, y);
                }
            }
        }
        for (int angle=0; angle < 3600; angle++)
        {
            RaycastHit hit;
            Physics.Raycast(transform.position, Quaternion.Euler(0, 0, angle/10) * Vector3.up, out hit);
            if (hit.collider!=null)
            {
                GameObject hitObject = hit.collider.gameObject;
                if (!check.Contains(hitObject)&&hitObject!=this)
                {
                    total += 1;
                    check.Add(hitObject);
                }
           }
        }
        return total;
    }
}

ฉันใช้ 3600 raycasts เพราะมันล้มเหลวในกรณีทดสอบที่ 5 ด้วยค่าที่ต่ำกว่า มันยังอาจล้มเหลวสำหรับกรณีทดสอบที่ใหญ่กว่า / แม่นยำยิ่งขึ้น

แต่น่าเสียดายที่ทั้ง WebGL และเดสก์ทอปสร้างดูเหมือนจะทำลายดังนั้นทั้งหมดที่ฉันต้องเป็นรหัสแหล่งที่มาเพื่อทดสอบบน GitHub


read: worse than Javaนี่คือ 383 ไบต์ที่สั้นกว่าโซลูชัน Java!
8397947

@dorukayhan ฉันหมายถึงว่าโดยส่วนใหญ่แล้วตัวที่มีความละเอียดมากกว่า Java
Blue

ฉันไม่รู้เกี่ยวกับ C # แต่คุณไม่สามารถแทนที่total+=1ด้วยได้total++หรือ ฉันคิดว่าอีกวิธีหนึ่งในการบันทึกตัวละครบางตัวคือการสร้างคิวบ์ของสิ่งปลูกสร้างและกำหนดตำแหน่งในหนึ่งคำสั่ง คุณดูเหมือนจะไม่ใช้cubeตัวแปรซ้ำทุกที่
Frozn

@ Frozn ฉันไม่ได้ทำอย่างนั้นจริงในรหัส golfed ของฉัน
Blue

เพิ่งดูรหัสและเห็นว่าคุณเปลี่ยนการนับที่นั่น ฉันมักจะคิดว่ารุ่น golfed เป็นรุ่นยาวกว่าช่องว่างของอีกต่อไป แต่นั่นไม่ใช่กรณีที่ชัดเจน เกี่ยวกับส่วนที่สอง: ฉันคิดว่าคุณทำ GameObject b=GameObject.CreatePrimitive(PrimitiveType.Cube);b.transform.position=new Vector3(x,y);มัน ฉันไม่รู้ว่าเป็นไปได้ใน C # แต่ใน Java สามารถเขียนGameObject.CreatePrimitive(PrimitiveType.Cube).transform.position=new Vector3(x,y);แทนได้
Frozn

3

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 ตัวอักษร!


Nice Golf! ฉันใช้เส้นทางที่ง่ายขึ้นด้วยการฉายรังสีแบบติดตั้งในตัวทั้งหมด แต่มันดีที่รู้ว่าฉันช่วย! (BTW ฉันอาจจะเปลี่ยนการตั้งค่าเช่นกัน)
บลู
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.