Altıgen bitişiklik


28

Örnek Altıgen Spiral

Yukarıdaki resim altıgen altıgen ızgarasını göstermektedir. Izgaradaki her bir hücreye, merkezden başlayarak ve gösterildiği gibi saat yönünün tersine spiral şeklinde bir indeks atanır. Kılavuzun süresiz olarak devam edeceğini unutmayın - yukarıdaki resim sadece ilk bölümdür. Bir sonraki altıgen 60 ve 37'ye bitişik olacaktır.

Göreviniz, bu ızgaradaki iki hücrenin bitişik olup olmadığını belirlemektir.

İki hücre endeksi verildiğinde, iki hücre bitişikse bir truthy değeri ve / veya eğer değilse bir falsey değeri basan / veren bir program veya fonksiyon yazın.

Pratik nedenlerle sınırlı değilse, kodunuz her boyuttaki giriş için teorik olarak çalışmalıdır.

Truthy test durumları:

0, 1
7, 18
8, 22
24, 45
40, 64
64, 65

Falsey test durumları:

6, 57
29, 90
21, 38
38, 60
40, 63
41, 39
40, 40

Bu yani bayt cinsinden en kısa cevap kazanır. Ezoterik olmayan diller için bile açıklamalar teşvik edilmektedir.

Yanıtlar:


7

Elixir , 263 257 264 223 214 218 214 bayt

a=fn x,y->i=&(&1*(&1-1)*3+1)
[x,y]=Enum.sort [x,y]
if x<1,do: y in 1..6,else: (y-x==1||fn->a=y-trunc i.((r=(:math.sqrt(12*x-3)+3)/6)+1)
t=trunc r
a in [0,1,rem(b=x-i.(t)+1, t)<1&&b-t*6!=0&&2]||b<2&&a==-1 end.())end

Çevrimiçi deneyin!

asılsız versiyon

def get_ring(x) do
    1/6*(:math.sqrt(12*x-3)+3)
end

def inv_get_ring(x), do: x*(x-1)*3+1

def ring_base(x), do: inv_get_ring(trunc(x))

def is_corner(x) do
    ring = trunc(get_ring(x))
    inv_ring = ring_base(ring)
    stuff = (x-inv_ring+1)
    rem(stuff, ring) == 0
end

def is_last(x),do: ring_base(get_ring(x)+1)-1 == x
def is_first(x),do: ring_base(get_ring(x)) == x

def hex_adj(x, y) do
    {x, y} = {min(x,y), max(x,y)}
    cond do 
        x == 0 ->y in 1..6      
        y-x==1 -> true
        true ->
            adj = trunc(inv_get_ring(get_ring(x)+1))
            number = if is_corner(x)&&!is_last(x), do: 2, else: 1
            if y-adj in 0..number do
                true
            else
                is_first(x) && y == adj-1
            end
    end
end
  • trunc(number) Sayının tamsayı kısmını döndürür
  • rem(a,b) A / b'nin kalanını döndürür
  • cond do end Bu, birçok zorunlu dilde büyük harf cümleleri varsa veya bu cümleleri değiştirirse eşdeğerdir

açıklama

get_ring (endeks)

Dizinin "halkasını" hesaplar.

Örnek: 1-6 için 1, 7-18 için 2, vb.

Bu sadece sonuç ederse geçerlidir floor. İzleyen basamaklar, bu döşemenin halkanın etrafında ne kadar uzakta olduğunu gösterir.

inv_get_ring (halka)

Tersini hesaplar get_ring(index).

ring_base (halka)

Halkadaki ilk döşemenin indeksini hesaplar.

is_corner (endeks)

Köşeler, dış halkada üç ayrı kiremitli karo bulunan karolardır. En içteki halka tamamen köşelerden oluşur.

Örnekler: 21,24,27,30,33,36

is_last (endeks)

Bu indeks, halkasındaki en yüksek ise doğrudur.

is_first (endeks)

Bu, halkanın taban döşemesiyse doğrudur.


2
Cevabı, son durum için bir düzeltme içerecek şekilde düzenledim :)
Garuno

Golf versiyonunuzu ilk tekrarlamaları takip ederek izledim ama yaklaşımınızı değiştirmiş gibisiniz. Mevcut golf versiyonunuz hala eski versiyona denk mi?
John Michael Yasası

Evet öyle! İksir'de satır içi değişkenleri açıklayabileceğinizi öğrendim. Bu bana kodun başında lambda işlevlerinden kurtulma yeteneği verdi. Daha verimli olabilmesi için değişkenleri bir parça karıştırdım.
Garuno

5

MATL , 47 45 44 43 41 bayt

s:"JH3/^6:^t5)w5:&)@qY"w@Y"]vYs0hG)d|Yo1=

Çevrimiçi deneyin! Veya tüm test durumlarını doğrulayın .

Bir bonus olarak, kod, kodun son bölümünü değiştirerek grafiksel olarak MATL Online'da görülebilen hücre merkezlerinin konumlarını izleyen altıgen bir spiral oluşturur .

açıklama

Genel fikir    Kod ilk önce birim adımda yeterince büyük altıgen bir spiral oluşturur. Spiral, hücre merkezlerinin pozisyonlarını temsil eden karmaşık sayılar vektörü olarak tanımlanır. Girdi numaraları ile o vektöre indeksleme ve mutlak farkın hesaplanması, belirtilen iki hücre arasındaki mesafeyi verir. Hücreler sadece sonuç 1 ise ve bitişiktir. Ancak, kayan nokta yanlışlıkları nedeniyle 1 ile karşılaştırılmadan önce yuvarlama gerekir.

Spiralin Yapımı Spiralin    , iki girişin toplamına eşit sayıda "katmanı" olacaktır. Bu (çok) gerekenden daha büyüktür ve girdi hücrelerinin spiralde bulunmasını sağlar.

Spirali oluşturmak için , ilk önce j 2/3 ( j hayali ünitedir) olan karmaşık sayı hesaplanır. Bunu, 1'den 6'ya kadar olan üstlere yükseltmek, temel bir yer değiştirmeler dizisini verir; öyle ki, yer değiştirmeleri takip etmek bir altıgeni izleyecektir. Bu altıgen, "kapalı" olması dışında, sarmalın en iç katmanını oluşturacaktır. Aslında, bu altıgenin son adımda "büyümesini" istiyoruz ve sonra spiralin bir sonraki katmanını oluşturmak için iki kat daha fazla (iki kişilik gruplar halinde hizalanmış) olmak üzere daha büyük altıgen izleriz; burada resme bakınız . Bir sonraki katman, ilk üç kattan üç kat puan kazanacaktır (üçlü gruplar halinde); buraya bakınız .

Bunu yapmak için, temel setten (güney-doğu yönünde işaret eden) beşinci yer değiştirme "büyüme" adımı olarak seçilmiştir. Katman k bu adımla başlar, ardından k kere tekrarlanan ilk beş temel adım takip eder, ardından altıncı adım (doğu yönü) k −1 defa tekrarlanır . Bu umutla, yukarıda bağlantılı iki şekle bakarak netleşir.

Tüm katmanlar dahil olmak üzere ortaya çıkan vektör, spirali izleyen karmaşık yer değiştirmeleri temsil eder. Kümülatif toplam, hücre merkezlerinin gerçek koordinatlarını verir.

Son olarak, 0'da bulunan ilk hücre, bu vektörün sonuna eklenir . Bunun nedeni MATL'nin modüler 1 tabanlı indeksleme kullanmasıdır ve indeks 0, dizinin son girişini ifade eder .

Bitişiklik için test    Girilen sayılarla verilen iki hücre seçilir, koordinatları çıkarılır ve mutlak değer yuvarlanır ve 1 ile karşılaştırılır.

Yorumlanan kod

s         % Implicitly input array of two numbers. Push their sum, say S
:         % Range [1 2 ... S]
"         % For each k in [1 2 ... S]
  J       %   Push 1j
  H3/     %   Push 2, then 3, then divide: gives 2/3
  ^       %   Power
  6:      %   Push [1 2 ... 6]
  ^       %   Element-wise power. This is the array of 6 basic displacements
  t5)     %   Duplicate. Get 5th entry
  w5:&)   %   Swap. Push subarray with entries 1st to 5th, then push 6th
  @qY"    %   Repeat the 6th displacement k-1 times
  w@Y"    %   Swap. Repeat 1st to 5th displacements k times
]         % End
v         % Concatenate everything into a column vector
Ys        % Cumulative sum. This gives the cell center coordinates
0h        % Append a 0
G)        % Index by the input vector
d|        % Absolute difference
Yo        % Round to nearest integer
1=        % Does it equal 1? Implicitly display

Bir açıklama ekler misiniz?
Shaggy

@Shaggy Genel bir açıklama ekledim. Açıksa bana bildirin (açıklamak zor). Yorumlanan kodu daha sonra ekleyeceğim
Luis Mendo

2

05AB1E (eski) , 30 29 27 bayt

α2‹i1q}1ݹ+v12y*3-tîÌy+}Ÿ²å

Çevrimiçi deneyin!

Kod açıklaması:

α2‹i1q}                     : if the absolute diff of the two number is 1 or 0 return 1
                          ²å: return that the second number is in
                         Ÿ  : range of {
       1Ý                   :  create [0, 1]
         ¹+                 :  add the first number to the elements
           v            }   :  map that list
            12y*3-tîÌy+     :  calculate the corresponding value where it's an adjacency
                                }

Matematiğin açıklaması:

Bu golfü yaparken yaklaşık 5 saatimi boşa harcadım. Kısacası girdilerin 2d grafiğini yapmaya başladım ve Xbirbirlerine bitişik olduklarını çizdim. Sonra bir kalıp buldum. OEIS ve tombala aradım ! Bu sırayı buldum ve web sitesinde verilen formülü kullandım.


1

C (gcc) , 175 173 bayt

Peter Taylor'a böcek yakaladığı için teşekkürler .

-2 bayt için ceilingcat sayesinde . Bu operatör benim ana kör noktam olmaya devam ediyor.

c,r,C,L;y(a){a=a<L*2?L-a:a<L*3?-L:a<5*L?a-L*4:L;}z(a){L=ceil(sqrt(a/3.+.25)-.5);C=y(a-=3*L*~-L);L?L=y((L+a)%(L*6)):0;}f(a,b){z(a);c=C,r=L;z(b);a=a-b&&(abs(c-C)|abs(r-L))<2;}

Çevrimiçi deneyin!

Bu yaklaşım, iki hücrenin sırasını ve sütununu bulmaya ve bunları karşılaştırmaya odaklanır; Herhangi bir komşu karşılık gelen koordinatlara 1'den fazla farklılık gösteremez. Merkezden dışarı doğru hareket ederken, her katmanın öncekinden 6 hücreye daha sahip olduğunu gözlemleriz. Her bir katman, L yüksek "göstergesi" bir şekilde 6 * açık olduğundan Bu durum, (L * (L - 1) * (L - 2) ...), ya da C = 6 * (L 2 + L) / 2 C burada "global" hücre numarasıdır. Etrafı karıştırırken, lise matematik geri dönüşleri veren L 2 + L - C / 3 = 0 olur. Bundan, tavan formül (sqrt (1/4 + C / 3) + 0.5) elde ediyoruz. Global bir hücre indeksini içine takarak hücrenin içinde bulunduğu katmanı alırız.

Her bir kattaki ilk hücre, doğal olarak önceki katınkinden daha yüksek olduğundan, L başlangıç = (6 * (L - 1) 2 + (L - 1)) / 2 (3 * (L) 'ye basittir. 2 - L). Bundan sonra katman indeksini alırız L index = C - L start .

Daha sonra, her katmanın altı L bölümden oluştuğunu görüyoruz, her biri L uzunlukta. Kuzeyden başlayarak ve saat yönünün tersine gidiyor, ilk iki bölüm için (1 <= L indeksi <= 2 * L) görüyoruz. , sütunu L - L indeksinden alıyoruz . Bir sonraki bölüm L * 2 <L indeksi <= L * 3, tek bir sütun -L paylaşan tüm hücrelere sahiptir. Sonraki iki bölüm L * 3 <L indeksi <= L * 5 şeklindedir, sütunları L indeksine göredir - L * 4. Ve son olarak altıncı bölümün hepsinin de hücreleri L sütunundadır. Üst sınırları bir adım boyunca kaydırabiliriz Koddaki bazı baytları kaydetmek için

Peki ya sıralar? Kodu tekrar kullanmak için, şebekeyi 44 hücre düz olacak şekilde çevirin. Daha sonra sütunlarla aynı mantığı kullanıyoruz ancak sonuçları bu sefer "satır" olarak adlandırıyoruz. Tabii ki, aslında bir ızgara açmak yerine, etrafındaki bir turun 1 / 6'sına giriyoruz.


@ PeterTaylor İyi yakalamak, teşekkürler!
gastropner

1

Python 3, 150 bayt

def h(a,b):
 L=[];i=1
 while len(L)<a+b:r=sum((i*[1j**(k/3)]for k in range(4,16,2)),[]);r[0]+=1;L+=r;i+=1
 return.9<abs(sum(L[min(a,b):max(a,b)]))<1.1

Benim çözümüm temel olarak yukarıdaki Luis Mendo ile aynı düşünce çizgisini takip ediyor. Daha okunaklı yazılırsa, kod açıklayıcıdır:

def h(a,b):
    L=[]
    i=1
    while len(L)<a+b:
        l=sum((i*[1j**(k/3)]for k in range(4,16,2)),[])
        l[0]+=1
        L+=l
        i+=1
return .9<abs(sum(L[min(a,b):max(a,b)]))<1.1
  1. işlev haşağıdakileri yapar:
  2. L listesi, her sayının (karmaşık) pozisyonlarını içerecektir.
  3. i çalma numarası.
  4. While döngüsünde, her yinelemede yeni bir halka eklenir. Ne kadar çalmaya ihtiyacımız olduğunu bulmak yerine, sadece + b içerecek kadar uzun olana kadar listeyi oluşturmaya devam ediyoruz, o zaman kesinlikle ikisini de içerecek kadar uzun.
  5. 'ring-list' l, step-vektörünün 6 (1) kat listesidir , step-vektörün bir güç için 1j ** (2/3) olduğu. Aralık, 0'dan başlamaz, 4'ten başlar, bu da tüm ızgaraların dönmesine neden olur. Bu benim yapmamı sağlıyor:
  6. l[0]+=1 Satır 6'da ki, bir halkadan diğerine adımdır.
  7. L+=l tam listeyi ve çalma listesini birleştirir.
  8. L listesi, sadece bir konum elde etmek için toplanması gereken (bütünleşik) olması gereken adım vektörlerini içerir. Buradaki en iyi özellik, dilimi uzaklıklarını almak için en düşük sayıdan en yüksek noktaya kadar toplayabilmemizdir ! Yuvarlama hataları nedeniyle sonuç tam olarak 1 olmaz, bu nedenle .9 <... <1.1. İlginç bir şekilde, sıfır durum h(0,0)veya h (0,1) dolaylı olarak halledilir, çünkü boş bir listenin toplamı sıfırdır. Ben emin olabilirsem a<b, yani argümanlar artan sırayla geleceğini, ben değiştirerek başka 14 bayt tıraş olabilir L[min(a,b):max(a,b)]ile L[a:b], ama ne yazık ki!

Not: Bunun eski bir zorluk olduğunu bilmiyordum, birkaç gün önce ortaya çıktı ve o zamandan beri beni dırdır etti.


Bu harika bir cevap! Geç cevap için endişelenmeyin, PPCG'de bununla ilgili gerçekten bir sorunumuz yok.
32'de

0

Mathematica, 111 105 104 bayt

r=Floor[(1+Sqrt[(4#-1)/3])/2]&;t=Limit[Pi(#/(3x)+1-x),x->r@#]&;p=r@#*Exp[I*t@#]&;Round@Abs[p@#-p@#2]==1&

Açıklama:

r=Floor[(1+Sqrt[(4#-1)/3])/2]&rgirdi alan #ve hücreye 0 olan mesafeyi (hücre sayısında) hesaplayan bir işlevi tanımlar. Bunu her mesafenin / halkanın son hücrelerinde modelden yararlanarak yapar: 0 = 3 (0 ^ 2 + 0), 6 = 3 (1 ^ 2 + 1), 18 = 3 (2 ^ 2 + 2), 36 = 3 (3 ^ 2 + 3), ... ve bu kalıp için formülü ters çevirerek. Hücre 0 için, gerçekte 0 + 0 * i = 0 elde etmek için bileşen-bilgiyi hesaplayan (1/2) + i * (sqrt (3) / 6) tabanını aldığını unutmayın .

İle rtanımlanan, r@#hücre için halka olan #(başka bir fonksiyon tanımlama içinde). #+3r@#-3(r@#)^2&kodda tam olarak görünmüyor, ancak bir hücrenin sayısını alıyor ve bir sonraki iç halkadaki en yüksek hücrenin sayısını çıkartıyor, böylece “mevcut halkanın hangi hücresi bu?” sorusuna cevap veriyor. Örneğin, hücre 9, halka 2'nin 3. hücresidir, yani r[9]2 çıktısı ve #+3r@#-3(r@#)^2&[9]3 çıktısı olacaktır.

Yukarıdaki işlevle yapabileceğimiz şey , "açılı hücre 0, hücre 17, hücre 58" ışından söz konusu hücreye kadar kutupsal açıyı , saat yönünün tersine açıyı bulmak için kullanmaktır . Her halkanın son hücresi daima Pi / 6 açısındadır ve Pi / (3 * ring_number) artışlarıyla bir halkanın etrafında gideriz. Dolayısıyla teoride Pi / 6 + (which_cell_of_the_current_ring) * Pi / (3 * ring_number) gibi bir şey hesaplamamız gerekiyor. Bununla birlikte, resmin döndürülmesi hiçbir şeyi etkilemez, bu yüzden Pi / 6 bölümünü silebiliriz (6 bayt kurtarmak için). Bunu önceki formülle birleştirip sadeleştirerek,Pi(#/(3r@#)+1-r@#)&

Ne yazık ki, bu hücre 0 için tanımsızdır, çünkü halka numarası 0'dır, bu yüzden bunu aşmamız gerekir. Doğal bir çözüm gibi bir şey olurdu t=If[#==0,0,Pi(#/(3r@#)+1-r@#)]&. Fakat 0 hücresi için açıyı umursamadığımızdan ve r@#tekrar edildiğinden dolayı , aslında burada bir byte kaydedebiliriz.t=Limit[Pi(#/(3x)+1-x),x->r@#]&

Şimdi halka numarasına ve açısına sahip olduğumuza göre, bir hücrenin konumunu (merkez) bulabiliriz, böylece bitişikliği test edebiliriz. Gerçek pozisyonu bulmak can sıkıcıdır, çünkü halkalar altıgendir, ancak halkaları mükemmel daireler gibi gösterebiliriz, böylece halka numarasını hücre 0'ın merkezine kadar olan mesafe olarak değerlendirebiliriz. kapat. Karmaşık bir sayının kutup şeklini kullanarak, bu yaklaşık konumu karmaşık düzlemde basit bir işlevle temsil edebiliriz :p = r@#*Exp[I*t@#] &;

Kompleks düzlemdeki iki karmaşık sayı arasındaki mesafe , farklarının mutlak değeri ile verilir ve daha sonra, yaklaşmadaki herhangi bir hatayı gidermek için sonucu yuvarlayabiliriz ve bunun 1'e eşit olup olmadığını kontrol edebiliriz. bu eserin bir ismi yok mu, ama Round@Abs[p@#-p@#2]==1&.


Şunları yapabilirsiniz çevrimiçi denemek içinde Wolfram Bulut kum havuzu :> "hücreyi değerlendirin" veya Shift + Enter isabet veya sayısal tuş takımı girin - Gear aşağıdaki gibi bir kodu yapıştırıp tıklayarak

r=Floor[(1+Sqrt[(4#-1)/3])/2]&;t=Limit[Pi(#/(3x)+1-x),x->r@#]&;p=r@#*Exp[I*t@#]&;Round@Abs[p@#-p@#2]==1&[24,45]

Veya tüm test durumları için:

r=Floor[(1+Sqrt[(4#-1)/3])/2]&;t=Limit[Pi(#/(3x)+1-x),x->r@#]&;p=r@#*Exp[I*t@#]&;Round@Abs[p@#-p@#2]==1&//MapThread[#,Transpose[{{0,1},{7,18},{8,22},{24,45},{40,64},{64,65},{6,57},{29,90},{21,38},{38,60},{40,63},{41,39},{40,40}}]]&
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.