都市:視界


18

私は無限の2次元都市の位置(0、0)にいます。これは各格子点を中心とするブロックに完全に分割されており、その一部には建物が含まれています。特定のポイント(x、y)にある建物は、(x-.5、y-.5)および (x + .5、y + .5)に反対側の角を持つ正方形全体を占めます。建物は、(0、0)から他の建物と交差しない建物内のポイントまでの線分がある場合にのみ表示されます。

たとえば、私()は次の都市に@6つの建物(*)を見ることができます。

  *
 *
*
*@
x**
 *  y

(-1、-1)xでマークされた建物は、隣接する2つによって遮られているため表示されません。または(1、-1)の建物の端で遮られているため、(3、-2)でマークされたもの。y

入力

複数行の文字列、または行のリスト。オプションで長方形にスペースを埋めます。以下のみが含まれます。

  • 単一@(私の位置)
  • スペース
  • *、建物を表します。

常に少なくとも1つの建物があるため、少なくとも1つの目に見える建物があります。

出力

目に見える建物の数。

テストケース

*@
1

* *******
 @     * 
7

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

   *
  **
@ **
2

*      *
 *    * 
@
4

@
 *
  ***
1

タイトルの @Geobitsに感謝します。



テストケース3については、8 *で囲まれていますが、結果は4です。しかし、これらのコーナーは他の建物によってブロックされていないようです。コーナーを含めないルールはありますか?
LukStorms

1
@LukStorms Minecraftのように、各星が実際に立方体であると想像してください。その真ん中に立っていた場合、4つのブロックしか見ることができません
ブルー

賞金を授与する前に、ゴルフソリューションを入力する前に(非常にすぐに)お待ちください。:)
レイフウィラーツ

回答:


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

ゴルフをしていない:

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

5番目のテストケースで失敗するため、3600レイキャストを使用しました。さらに大きい/より正確なテストケースでは、依然として失敗する可能性があります。

残念ながら、webglビルドとデスクトップビルドの両方が壊れているように見えるので、私が持っているのはgithubでテストするソースコードだけです。


read: worse than Javaこれは、Javaソリューションよりも383バイト短いです!
user8397947

@dorukayhanほとんどのビルトインはJavaよりも冗長です
ブルー

私はC#のことは知らないが、あなたは置き換えることができなかったtotal+=1total++?一部のキャラクターを保存する別の方法は、建物の立方体を作成し、1つのステートメントでその位置を設定することだと思います。cubeどこでも変数を再利用していないようです。
Frozn

@Frozn私は実際にはゴルフのコードでそれをしていません
ブルー

コードを見て、そこでカウントを変更したことがわかりました。私は常に、ゴルフバージョンは長いものの空白を取り除いたバージョンであると仮定しますが、明らかにここではそうではありません。第二部について:私はあなたがすると思います。です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がやったように、ある種のレイキャスティングについて考えました。少しの進歩もなかったので、私はその挑戦を片付けました。その後、ブルーの答えを見て、次の簡単なアイデアが思い浮かびました。各建物は、他には何も見えない角度をブロックしています。見えるものと、他の建物によってすでに隠されているものを追跡する必要があります。それでおしまい!

このアルゴリズムは次のように機能します。人までの距離が最も短い建物を決定します。次に、人から建物の隅まで描かれた4本の線を想像します。これらのうちの2つには極端な値があります。建物が見える最小角度と最大角度。それらを範囲として取り、それらを見ることができることがわかっている他の建物と比較します(最初はありません)。範囲は重複していても、お互いを含んでいても、まったく触れていなくてもかまいません。範囲を比較し、表示可能な建物に隠れていない建物の新しい範囲を取得します。見えている建物と比較した後に何かが残っている場合、その建物も見ることができます。残りの角度範囲を範囲のリストに追加して、次に長い距離の次の建物と比較して開始します。

場合によっては、範囲が0度の範囲で重なり合うことがあります。これらの範囲は、表示されない建物を誤って追加しないようにフィルターされます。

誰かがこの説明を理解してくれることを望みます:)

私はこのコードがあまりゴルフされていないことを知っています、私はできるだけ早くこれをします。

それは本当にやりがいのある仕事でした。うまくいく解決策を見つけたと思っていましたが、代わりにあなたはまだ遠くにいます。このソリューションはかなりうまくいくと思います。それは非常に高速ではありませんが、少なくとも動作します;)そのパズルをありがとう!


更新

私はすべてを1つの関数にゴルフする時間を見つけたので、それをラムダに変えることができます。すべての関数は一度だけ呼び出されたため、1つのメソッドに入れることができます。リストからセットに切り替えると、追加の文字が保存されます。宣言はまとめられています。比較がまとめられ、文字がASCII値に置き換えられました。範囲の比較は、多くの3項として表現できます。Double.NEGATIVE_INFINITYのような長い式を防ぐために、あちこちでいくつかのトリックが行われました。可能な場合、インライン割り当てが行われます。もう少し節約するために、角度を度で比較することからラジアンを比較することに切り替えました。変更全体で500文字以上が保存されましたが、すべて1000文字未満にしたいと考えています;)

可能な場合はジェネリックを削除し、1つの要素配列を作成して戻り値の比較を短縮し、代わりにその値を確認しました。Double.NEGATIVE_INFINITYもPI2と-PI2に置き換えました。これらは角度の上限と下限です。ついに1000文字以下になりました!

人物の場所と建物のイテレーターを見つけるためのループをマージして、いくつかのキャラクターを保存しました。残念ながら、これにはループから戻り値を移動し、今度はラベルなしでブレークを使用する必要があります。私はマージmaxdistanceSquaredminそしてnewDistanceSquared同時にそれらは必要ではないので。に変更Integer.MAX_VALUEしました2e31-1。またhalf = 0.5、建物の角を計算するために使用される定数を作成しました。これは、ゴルフバージョンでは短くなります。全体で、さらに30文字を節約しました!


素敵なゴルフ!私はすべての組み込みのレイキャスティングで簡単なルートを取りましたが、助けてくれたことを知ってうれしいです!(ところで私もおそらくセットに変更します)
ブルー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.