Şehirler: Manzaralar


18

Her biri örgü noktasında ortalanmış bloklara mükemmel şekilde bölünmüş, bazıları bina içeren sonsuz iki boyutlu bir şehrin (0, 0) pozisyonundayım . Belirli bir noktadaki (x, y) bir bina , kenarlığı da dahil olmak üzere (x-.5, y-.5) ve (x + .5, y + .5) köşelerinde karşıt köşeleri olan tüm kareyi kaplar . (0, 0) ' dan binada başka bir bina ile kesişmeyen bir noktaya kadar bir çizgi bölümü varsa, bir bina görülebilir .

Örneğin, ben aşağıdaki şehirde @6 bina ( *) görebiliyorum :

  *
 *
*
*@
x**
 *  y

Bir işaretli bina göremez xde, (-1 1) kendisine komşu iki ile tıkalı çünkü; veya (1, -1) binasının kenarı tarafından engellendiği yiçin (3, -2) ile işaretli olan .

Giriş

Çok satırlı bir dize veya satır listesi, isteğe bağlı olarak boşluklarla bir dikdörtgene doldurulur. Yalnızca şunları içerecektir:

  • tek @(konumum)
  • Spaces
  • *binaları temsil eder.

Her zaman en az bir bina ve dolayısıyla en az bir görünür bina olacaktır.

Çıktı

Görünür bina sayısı.

Test senaryoları

*@
1

* *******
 @     * 
7

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

   *
  **
@ **
2

*      *
 *    * 
@
4

@
 *
  ***
1

Başlık için @Geobits'e teşekkürler .



Test durumu 3 hakkında, 8 * ile çevrilidir, ancak sonuç 4'tür. Ancak bu köşeler diğer binalar tarafından engellenmiş gibi görünmemektedir. Köşeleri dahil etmemek için bir kural var mı?
LukStorms

1
@LukStorms Yıldızların her birinin aslında minecraft'ta olduğu gibi küp olduğunu hayal edin. Eğer bunun ortasında
Blue

Ödül vermeden önce golf çözümüme (çok yakında) girmeden önce beklemek çok nazik olur muydu? :)
Leif Willerts

Yanıtlar:


4

Birlik + C #, 589 bayt

Bu muhtemelen bir kod golf yapmak için en kötü dildir (okuma: Java'dan daha kötü), ancak Unity bu meydan okuma için çok yararlı bir özellik ile birlikte geliyor.

EDIT: birkaç boşluk kaçırdı, sayaç uzunluğunu döndürür, sayaç değil

golfed:

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 rekat kullandım çünkü 5. test senaryosunu daha düşük başarısızlıkla sonuçlandı. Daha büyük / daha kesin test durumlarında bile başarısız olabilir.

Ne yazık ki, hem webgl hem de masaüstü yapıları kırılıyor gibi görünüyor, bu yüzden sahip olduğum tek şey github üzerinde test edilecek kaynak kodu .


read: worse than JavaBu, Java çözümünden 383 bayt daha kısa !
user8397947

@dorukayhan Yani çoğu yerleşik tarafından Java daha ayrıntılı
Blue

Ben C # bilmem ama yerini could total+=1ile total++? Bazı karakterleri kaydetmenin başka bir yolunun binanın küpünü oluşturmak ve bir ifadede konumunu ayarlamak olduğunu düşünüyorum. cubeDeğişkeni hiçbir yerde yeniden kullanmıyorsunuz.
Frozn

@Frozn Aslında bunu golf kodumda yapmıyorum
Blue

Sadece koda baktım ve oradaki sayımı değiştirdiğinizi gördüm. Her zaman golf sürümünün daha uzun olanın boşluk bırakılmış bir versiyonu olduğunu varsayıyorum, ama buradaki durum böyle değil. İkinci bölümle ilgili: Sanırım öyle. Öyle GameObject b=GameObject.CreatePrimitive(PrimitiveType.Cube);b.transform.position=new Vector3(x,y);. C # mümkün olup olmadığını bilmiyorum ama Java bir GameObject.CreatePrimitive(PrimitiveType.Cube).transform.position=new Vector3(x,y);yerine yazabilir .
Frozn

3

Java 8 lambda, 1506 1002 972 942 karakter

Bu meydan okumayı yenmek istedim, çünkü çok ilginç. Sonuç (çok golf değil) burada görülebilir:

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

Tabii ki bu da ungolfed versiyonunda var:

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

Bu yüzden çok zor görünüyor ama birinin düşündüğünden çok daha kolay. İlk fikrim, konumumdan binaya bir hattın herhangi bir kavşak olmadan yapılıp yapılamayacağını kontrol etmek için bazı kavşak algoritmaları kullanmaktı. Bunu yapmak için Cohen-Sutherland algoritmasını kullanmaya ve binanın dört köşesine de çizgiler çizmeye karar verdim. Bu ilk testler için oldukça işe yaradı, ancak sonuncusu başarısız oldu. Kısa süre sonra, köşeleri göremediğiniz bir kenarın bir kısmını görebileceğiniz bir durum olduğunu öğrendim. Ben de @Blue gibi bir tür ray döküm düşündüm. İlerlemediğim için bu zorluğu ortadan kaldırdım. Sonra Blue'nun cevabını gördüm ve aklıma şu basit fikir geldi: Her bina, başka hiçbir şeyin göremeyeceği bir açı engelliyor. Sadece nelerin görülebildiğini ve diğer binalar tarafından neyin gizlendiğini takip etmem gerekiyor. Bu kadar!

Algoritma şu şekilde çalışır: Kişiye en kısa mesafedeki binayı belirler. Sonra kişiden binanın köşelerine dört çizgi çizildiğini hayal ediyoruz. Bunlardan ikisinin aşırı bir değeri vardır: Binanın görülebileceği minimum ve maksimum açı. Onları bir menzil olarak alıyoruz ve görülebileceğini bildiğimiz diğer binalarla karşılaştırıyoruz (başlangıçta yok). Aralıklar üst üste gelebilir, birbirini içerebilir veya hiç dokunmaz. Aralıkları karşılaştırıyorum ve görüntülenebilir binalar tarafından gizlenmeyen bazı yeni aralıklar elde ediyorum. Görünürdeki binalar ile karşılaştırıldıktan sonra kalan bir şey varsa, bina da görülebilir. Kalan açı aralığını karşılaştırılacak aralıklar listesine ekliyoruz ve bir sonraki binaya bir sonraki daha uzun mesafeyle başlıyoruz.

Bazen aralıklar, 0 derecelik bir aralıkla sonuçlanacak şekilde çakışabilir. Bu aralıklar, görüntülenemeyen bir binayı yanlışlıkla eklemeyecek şekilde filtrelenecektir.

Umarım birisi bu açıklamayı anlar :)

Bu kod çok golf değil biliyorum, ben asap yapacağım.

Bu gerçekten zor bir işti. İşe yarayan bir çözüm bulduğunuzu düşündünüz, ancak bunun yerine çok uzaktasınız. Bence bu çözüm gayet iyi çalışıyor. Çok hızlı değil ama en azından işe yarıyor;) Bu bulmaca için teşekkürler!


Güncelleme

Her şeyi tek bir fonksiyona indirmenin zamanını buldum, bu da bir lambdaya dönüştürülebilir. Tüm fonksiyonlar sadece bir kez çağrıldı ve böylece tek bir yönteme dahil edilebilir. Bazı ek karakterleri kaydettiğinden listelerden setlere geçtim. Beyanlar bir araya getirildi. Karşılaştırmalar bir araya getirildi ve karakterlerin yerine ascii değeri geldi. Aralık karşılaştırması birçok üçlü olarak ifade edilebilir. Double.NEGATIVE_INFINITY gibi uzun ifadeleri önlemek için burada ve bazı püf noktaları yapıldı. Mümkün olan hallerde satır içi değerlendirmeler yapılır. Biraz daha fazla tasarruf etmek için açıları derece ile karşılaştırıp radyanları karşılaştırmaya geçtim. Tüm değişiklik 500'den fazla karakter kurtardı, umarım hepsini 1000'in altında almayı umuyorum;)

Mümkün olduğunca jenerikleri kaldırdım ve bir eleman dizisi oluşturarak dönüş karşılaştırmasını kısalttım ve bunun yerine değerini kontrol ettim. Ayrıca açıların üst ve alt sınırları olduğu için Double.NEGATIVE_INFINITY'yi PI2 ve -PI2 ile değiştirdim. Şimdi nihayet 1000 karakter uzunluğunda!

Kişilerin yerini bulmak için döngüleri birleştirdim ve bazı karakterleri kaydetmek için bina yineleyicisini kullandım. Ne yazık ki bu, dönüşü döngüden çıkarmamızı ve hala bir mola vermemizi gerektiriyor, ancak bu sefer etiketsiz. Ben birleşti maxve distanceSquaredve minve newDistanceSquaredaynı anda gerekmez olarak. Değiştim Integer.MAX_VALUEiçin 2e31-1. Ayrıca half = 0.5binanın köşelerini hesaplamak için kullanılan bir sabit oluşturdum . Bu, golf versiyonunda daha kısadır. Genel olarak 30 karakter daha kaydettik!


Güzel Golf! Tüm yerleşik yarışlarla daha kolay bir rota izledim, ancak yardımcı olduğumu bilmek güzel! (BTW Muhtemelen setlere de değişeceğim)
Blue
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.