도시 : 명소


18

나는 무한한 이차원 도시의 위치 (0, 0) 에 있으며, 각 격자 지점을 중심으로 한 블록으로 완벽하게 나뉘어져 있으며, 그중 일부에는 건물이 있습니다. 특정 지점 (x, y) 에있는 건물 은 경계를 포함하여 (x-.5, y-.5)(x + .5, y + .5)에 반대쪽 모서리가있는 전체 정사각형을 차지합니다 . (0, 0) 에서 다른 건물과 교차하지 않는 지점에 선 세그먼트가있는 경우 건물이 보입니다 .

예를 들어, 다음 도시에서 나 ( @6)는 6 개의 건물 ( *)을 볼 수 있습니다 .

  *
 *
*
*@
x**
 *  y

건물 옆 x(-1, -1)이 표시되어있는 것을 볼 수 없습니다 . 인접한 두 건물에 의해 가려져 있기 때문입니다. 또는 (1, -1) 건물 의 가장자리에 의해 막혀 있기 때문에 yat (3, -2) 로 표시된 건물.

입력

선택적으로 공백으로 채워진 여러 줄 문자열 또는 줄 목록. 다음 만 포함합니다 :

  • 싱글 @(내 위치)
  • 공백
  • *건물을 나타냅니다.

항상 하나 이상의 건물이 있으므로 하나 이상의 보이는 건물이 있습니다.

산출

보이는 건물의 수입니다.

테스트 사례

*@
1

* *******
 @     * 
7

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

   *
  **
@ **
2

*      *
 *    * 
@
4

@
 *
  ***
1

제목 으로 @Geobits에게 감사드립니다 .



테스트 사례 3에 대해서는 8 *로 둘러싸여 있지만 결과는 4입니다. 그러나 그 코너는 다른 건물에 의해 막히지 않은 것 같습니다. 모서리를 포함하지 않는 규칙이 있습니까?
LukStorms 2018 년

1
@LukStorms 각 별이 실제로 마인 크래프트처럼 큐브라고 상상해보십시오. 그 중간에 서 있었다면 4 개의 블록 만 볼 수있을 것입니다
Blue

현상금을 수여하기 전에 골프 솔루션에 들어가기 전에 (아주 빨리) 기다리기를 원하십니까? :)
Leif Willerts

답변:


4

유니티 + 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;}}

언 골프 드 :

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 레이 캐스트는 5 번째 테스트 사례가 더 낮기 때문에 사용했습니다. 더 크고 더 정확한 테스트 사례에서는 여전히 실패 할 수 있습니다.

불행히도 webgl과 데스크톱 빌드 모두 깨지는 것처럼 보이므로 github 에서 테스트 할 소스 코드 만 있으면 됩니다.


read: worse than Java이것은 Java 솔루션보다 383 바이트 습니다!
user8397947

@dorukayhan 나는 대부분의 빌트인이 Java보다 더 장황하다는 것을 의미합니다.
Blue

전 C #에 대해 알고하지 않습니다하지만 당신은 대체 할 수 total+=1와 함께 total++? 일부 문자를 저장하는 다른 방법은 건물의 큐브를 만들고 한 문장에서 위치를 설정하는 것입니다. cube어디에서나 변수 를 재사용하지 않는 것 같습니다 .
Frozn

@Frozn 저는 골프 코드에서 실제로 그렇게하지 않습니다
Blue

코드를 살펴보고 카운트를 변경 한 것을 확인했습니다. 필자는 항상 골프 버전이 더 긴 버전의 공백 버전이라고 가정하지만 분명히 그렇지 않습니다. 두 번째 부분에 관해서는 : 나는 당신이 생각합니다. 그것은이다 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

자바 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;
    }
}

그래서 그것은 매우 어려워 보이지만 생각보다 쉽습니다. 첫 번째 아이디어는 교차 알고리즘을 사용하여 내 위치에서 건물까지의 선을 교차없이 만들 수 있는지 확인하는 것이 었습니다. 이를 위해 Cohen-Sutherland 알고리즘을 사용하기로 결정하고 건물의 네 구석에 선을 그렸습니다. 이것은 첫 번째 테스트에서 잘 작동했지만 마지막 테스트는 실패했습니다. 나는 곧 모서리를 볼 수 없지만 가장자리의 일부를 볼 수있는 경우라는 것을 알았습니다. @Blue와 같은 일종의 레이 캐스팅에 대해 생각했습니다. 나는 진전이 없었기 때문에 그 도전을 멀리했습니다. 그런 다음 Blue의 답변을 보았고 다음과 같은 간단한 아이디어가 떠 올랐습니다. 각 빌딩 블록은 볼 수없는 각도를 가지고 있습니다. 볼 수있는 것과 다른 건물에 의해 이미 숨겨져있는 것을 추적하면됩니다. 그게 다야!

알고리즘은 다음과 같이 작동합니다. 사람과의 거리가 가장 작은 건물을 결정합니다. 그런 다음 사람에서 건물 모서리까지 네 개의 선이 그려지는 것을 상상해보십시오. 이 중 두 가지는 극단적 인 가치를 지닙니다. 건물을 볼 수있는 최소 및 최대 각도. 우리는 그것들을 범위로 가져 와서 그들이 볼 수 있다는 것을 알고있는 다른 건물과 비교합니다 (처음에는 없음). 범위가 겹치거나 서로 포함되거나 전혀 닿지 않을 수 있습니다. 나는 범위를 비교하고 볼 수있는 건물에 의해 숨겨지지 않은 건물의 새로운 범위를 얻습니다. 통찰력있는 건물과 비교 한 후 남은 것이 있으면 건물도 볼 수 있습니다. 나머지 각도 범위를 범위 목록에 추가하여 다음 거리와 함께 다음 건물과 비교하고 시작합니다.

때로는 범위가 0 도의 범위에서 겹치는 방식으로 겹칠 수 있습니다. 이 범위는 볼 수없는 건물을 실수로 추가하지 않도록 필터링됩니다.

누군가 가이 설명을 이해하기를 바랍니다 :)

나는이 코드가 많이 골프되지 않는다는 것을 알고 있습니다.

그것은 정말 어려운 작업이었습니다. 당신은 당신이 효과가있는 해결책을 찾았다 고 생각했지만 대신 여전히 멀리 있습니다. 이 솔루션은 꽤 잘 작동한다고 생각합니다. 그것은 빠르지는 않지만 적어도 작동합니다.) 그 퍼즐에 감사드립니다!


최신 정보

나는 모든 것을 하나의 기능으로 골프화하는 시간을 발견했다. 따라서 람다로 바뀔 수있다. 모든 함수는 한 번만 호출되었으므로 하나의 메소드에 넣을 수 있습니다. 추가 문자를 저장하기 때문에 목록에서 세트로 전환했습니다. 선언이 합쳐졌습니다. 비교가 이루어지고 문자가 ASCII 값으로 대체되었습니다. 범위 비교는 많은 삼항으로 표현할 수 있습니다. Double.NEGATIVE_INFINITY와 같은 긴 식을 방지하기 위해 여기 저기 몇 가지 트릭이 있습니다. 가능한 경우 인라인 어설 션이 수행됩니다. 조금 더 절약하기 위해 각도를 각도로 비교하는 것에서 라디안을 비교하는 것으로 전환했습니다. 전체 변경 사항은 500자를 초과하지 않았으므로 1000 미만으로 줄 이길 바랍니다.)

가능한 경우 제네릭을 제거하고 하나의 요소 배열을 만들어 반환 비교를 단축하고 대신 값을 확인하십시오. 또한 Double.NEGATIVE_INFINITY를 각도의 상한 및 하한으로 PI2 및 -PI2로 바꿨습니다. 이제는 1000 자 미만입니다!

사람 위치와 건물 반복자를 찾기 위해 루프를 병합하여 일부 문자를 저장했습니다. 불행히도 이것은 루프에서 리턴을 이동시키고 여전히 레이블을 사용하지 않고 휴식을 사용해야합니다. 나는 합병 maxdistanceSquaredminnewDistanceSquared그들이 동시에 필요하지 않습니다한다. 로 변경 Integer.MAX_VALUE했습니다 2e31-1. 또한 half = 0.5건물의 모서리를 계산하는 데 사용되는 상수 를 만들었습니다 . 골프 버전에서는 더 짧습니다. 전반적으로 우리는 또 다른 30자를 저장했습니다!


좋은 골프! 모든 내장 레이 캐스팅으로 더 쉬운 길을 갔지만 도움이되었습니다. (BTW 나도 세트로 변경 될 것입니다)
Blue
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.