Thành phố: Điểm tham quan


18

Tôi đang ở vị trí (0, 0) của một thành phố hai chiều vô tận, được phân chia hoàn hảo thành các khối tập trung tại mỗi điểm mạng, một số trong đó có các tòa nhà. Một tòa nhà tại một điểm nhất định (x, y) chiếm toàn bộ hình vuông với các góc đối diện tại (x-.5, y-.5)(x + .5, y + .5) , bao gồm cả đường viền của nó. Một tòa nhà có thể nhìn thấy được nếu có một số đoạn từ (0, 0) đến một điểm trong tòa nhà không giao với bất kỳ tòa nhà nào khác.

Ví dụ: tôi (the @) có thể thấy 6 tòa nhà ( *) trong thành phố sau:

  *
 *
*
*@
x**
 *  y

Tôi không thể thấy tòa nhà được đánh dấu bằng x, tại (-1, -1) vì nó bị cản trở bởi hai tòa nhà liền kề với nó; hoặc một đánh dấu bằng một ylúc (3, -2) bởi vì nó bị che khuất bởi các cạnh của (1, -1) xây dựng.

Đầu vào

Một chuỗi nhiều dòng hoặc danh sách các dòng, tùy ý đệm với các khoảng trắng thành một hình chữ nhật. Nó sẽ chỉ chứa:

  • một @(vị trí của tôi)
  • Không gian
  • *, đại diện cho các tòa nhà.

Sẽ luôn có ít nhất một tòa nhà, và do đó ít nhất một tòa nhà có thể nhìn thấy.

Đầu ra

Số lượng các tòa nhà có thể nhìn thấy.

Các trường hợp thử nghiệm

*@
1

* *******
 @     * 
7

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

   *
  **
@ **
2

*      *
 *    * 
@
4

@
 *
  ***
1

Cảm ơn @Geobits cho tiêu đề .



Về trường hợp thử nghiệm 3, nó được bao quanh bởi 8 * nhưng kết quả là 4. Nhưng những góc đó dường như không bị chặn bởi các tòa nhà khác. Có một quy tắc không bao gồm các góc?
LukStorms

1
@LukStorms Hãy tưởng tượng mỗi ngôi sao thực sự là hình khối, giống như trong minecraft. Nếu bạn đang đứng ở giữa đó, bạn sẽ chỉ có thể nhìn thấy 4 khối
Blue

Bạn sẽ thật tử tế khi chờ đợi trước khi tôi tham gia giải pháp chơi gôn của mình (rất sớm) trước khi trao giải thưởng? :)
Leif Willerts

Câu trả lời:


4

Thống nhất + C #, 589 byte

Đây có lẽ là ngôn ngữ tồi tệ nhất để chơi golf mã (đọc: tệ hơn Java), nhưng Unity đi kèm với rất nhiều tính năng hữu ích cho thử thách này.

EDIT: bỏ lỡ một vài khoảng trắng, trả về độ dài danh sách, không truy cập

Chơi gôn

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

Ung dung:

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

Tôi đã sử dụng 3600 lần phát sóng vì nó không thành công trong trường hợp thử nghiệm thứ 5 với mức thấp hơn. Nó vẫn có thể thất bại cho các trường hợp thử nghiệm lớn hơn / chính xác hơn.

Thật không may, cả hai bản dựng webgl và máy tính để bàn dường như bị hỏng, vì vậy tất cả những gì tôi có là mã nguồn để kiểm tra trên github .


read: worse than JavaĐây là 383 byte ngắn hơn so với giải pháp Java!
dùng8397947

@dorukayhan Ý tôi là hầu hết các phần mềm dựng sẵn đều dài dòng hơn Java
Blue

Tôi không biết về C # nhưng bạn không thể thay thế total+=1bằng total++? Tôi nghĩ một cách khác để cứu một số nhân vật là tạo khối lập phương và đặt vị trí của nó trong một câu lệnh. Bạn dường như không sử dụng lại cubebiến ở bất cứ đâu.
Frozn

@Frozn Tôi thực sự không làm điều đó trong mã đánh gôn của mình
Blue

Chỉ cần nhìn vào mã và thấy rằng bạn đã thay đổi việc đếm ở đó. Tôi luôn cho rằng phiên bản chơi gôn chỉ là phiên bản bị tước khoảng trắng của phiên bản dài hơn, nhưng rõ ràng đó không phải là trường hợp ở đây. Về phần thứ hai: Tôi nghĩ bạn làm. Đó là GameObject b=GameObject.CreatePrimitive(PrimitiveType.Cube);b.transform.position=new Vector3(x,y);. Tôi không biết liệu nó có thể có trong C # hay không nhưng trong Java người ta có thể viết GameObject.CreatePrimitive(PrimitiveType.Cube).transform.position=new Vector3(x,y);thay thế.
Frozn

3

Java 8 lambda, 1506 1002 972 942 ký tự

Tôi muốn đánh bại thử thách này, vì nó rất thú vị. Kết quả (không phải là rất golf) có thể được nhìn thấy ở đây:

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

Tất nhiên điều này cũng tồn tại trong phiên bản chưa được chỉnh sửa:

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

Vì vậy, nó có vẻ rất khó khăn nhưng nó dễ hơn mọi người nghĩ. Ý tưởng đầu tiên của tôi là sử dụng một số thuật toán giao cắt để kiểm tra xem một đường từ vị trí của tôi đến tòa nhà có thể được thực hiện mà không có bất kỳ giao lộ nào không. Để làm điều này, tôi quyết định sử dụng thuật toán Cohen-Sutherland và vẽ các đường thẳng cho tất cả bốn góc của tòa nhà. Điều này làm việc khá tốt cho các thử nghiệm đầu tiên, nhưng thử nghiệm cuối cùng đã thất bại. Tôi sớm phát hiện ra rằng đó là trường hợp bạn không thể nhìn thấy các góc mà là một phần của cạnh. Vì vậy, tôi đã nghĩ về một số loại đúc tia như @Blue đã làm nó. Tôi đặt thử thách đó đi, vì tôi không có chút tiến bộ nào. Sau đó, tôi thấy câu trả lời của Blue và ý tưởng đơn giản sau đây xuất hiện trong đầu tôi: Mỗi tòa nhà chặn một số góc mà không có gì khác có thể nhìn thấy. Tôi chỉ cần theo dõi những gì có thể nhìn thấy và những gì đã bị ẩn bởi các tòa nhà khác. Đó là nó!

Thuật toán hoạt động như sau: Nó xác định tòa nhà có khoảng cách nhỏ nhất với người. Sau đó, chúng tôi tưởng tượng bốn đường được vẽ từ người đến các góc của tòa nhà. Hai trong số này có một giá trị cực trị: Góc tối thiểu và tối đa mà tòa nhà có thể được nhìn thấy. Chúng tôi xem chúng như một phạm vi và so sánh chúng với các tòa nhà khác mà chúng tôi biết rằng chúng có thể được nhìn thấy (không có gì ở đầu). Các phạm vi có thể chồng lấp, bao gồm lẫn nhau hoặc không chạm vào tất cả. Tôi so sánh các phạm vi và nhận được một số phạm vi mới của tòa nhà không bị ẩn bởi các tòa nhà có thể xem được. Nếu có một cái gì đó còn lại sau khi so sánh nó với các tòa nhà trong tầm nhìn, tòa nhà cũng có thể xem được. Chúng tôi thêm phạm vi góc còn lại vào danh sách các phạm vi để so sánh và bắt đầu với tòa nhà tiếp theo với khoảng cách dài hơn tiếp theo.

Đôi khi các phạm vi có thể trùng nhau theo cách mà tôi kết thúc với phạm vi 0 độ. Các phạm vi này sẽ được lọc để không nhầm lẫn thêm một tòa nhà thậm chí không thể xem được.

Tôi hy vọng ai đó hiểu lời giải thích này :)

Tôi biết mã này không được đánh gôn nhiều, tôi sẽ làm điều này càng sớm càng tốt.

Đó là một nhiệm vụ thực sự thách thức. Bạn nghĩ rằng bạn đã tìm thấy một giải pháp hiệu quả nhưng thay vào đó bạn vẫn ở xa. Tôi nghĩ rằng giải pháp này hoạt động khá tốt. Nó không nhanh lắm nhưng ít nhất là nó hoạt động;) Cảm ơn vì câu đố đó!


Cập nhật

Tôi đã tìm thấy thời gian để chơi golf toàn bộ thành một chức năng duy nhất, do đó có thể biến thành lambda. Tất cả các hàm chỉ được gọi một lần và do đó có thể được đưa vào một phương thức. Tôi đã chuyển từ danh sách sang bộ vì điều này sẽ lưu một số ký tự bổ sung. Các tờ khai đã được đặt cùng nhau. Các so sánh đã được đặt cùng nhau và các ký tự được thay thế bằng giá trị ascii. Phạm vi so sánh có thể được thể hiện như nhiều chim nhạn. Một số thủ thuật ở đây và ở đó để ngăn chặn các biểu thức dài như Double.NEGECT_INFINITY đã được thực hiện. Trường hợp có thể khẳng định nội tuyến được thực hiện. Để tiết kiệm hơn một chút, tôi chuyển từ so sánh các góc theo độ sang so sánh radian. Toàn bộ thay đổi đã lưu hơn 500 ký tự, tôi hy vọng sẽ có được tất cả dưới 1000 ký tự;)

Tôi đã loại bỏ các tổng quát khi có thể và rút ngắn so sánh trả về bằng cách tạo một mảng một phần tử và thay vào đó kiểm tra giá trị của nó. Tôi cũng đã thay thế Double.NEGECT_INFINITY bằng PI2 và -PI2 vì đây là giới hạn trên và dưới của các góc. Bây giờ cuối cùng nó cũng dài dưới 1000 ký tự!

Tôi đã hợp nhất các vòng lặp để tìm vị trí người và trình vòng lặp tòa nhà để lưu một số ký tự. Thật không may, điều này đòi hỏi chúng ta phải di chuyển trở lại khỏi vòng lặp và vẫn sử dụng thời gian nghỉ nhưng lần này không có nhãn. Tôi sáp nhập maxdistanceSquaredminnewDistanceSquaredkhi họ không phải cùng một lúc. Tôi đổi Integer.MAX_VALUEthành 2e31-1. Ngoài ra tôi đã tạo ra một hằng số half = 0.5được sử dụng để tính toán các góc của tòa nhà. Đây là ngắn hơn trong phiên bản golf. Nhìn chung, chúng tôi đã lưu thêm 30 ký tự!


Golf tốt đẹp! Tôi đã đi một con đường dễ dàng hơn với tất cả các chương trình raycast tích hợp, nhưng thật tuyệt khi biết tôi đã giúp! (BTW tôi có thể cũng sẽ thay đổi thành các bộ)
Blue
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.