육각 인접


28

육각 나선 예

위의 이미지는 육각형의 육각형 격자를 표시합니다. 그리드의 각 셀에는 중앙에서 시작하여 그림과 같이 시계 반대 방향으로 나선형으로 인덱스가 할당됩니다. 그리드는 무한정 계속됩니다. 위의 그림은 단순히 첫 번째 섹션입니다. 다음 육각형은 60과 37에 인접합니다.

당신의 임무는이 격자에 주어진 두 셀이 인접 해 있는지 확인하는 것입니다.

두 개의 셀 인덱스가 주어지면 두 셀이 인접하면 참 값을 인쇄 / 반환하고 그렇지 않으면 거짓 값을 인쇄 / 반환하는 프로그램 또는 함수를 작성하십시오.

실제적인 이유로 제한되지 않는 경우 코드는 이론적으로 모든 크기의 입력에서 작동해야합니다.

확실한 테스트 사례 :

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

이것은 이므로 바이트 단위의 최단 답변이 이깁니다. 비 종교적 언어에 대해서도 설명이 권장됩니다.

답변:


7

엘릭서 , 263 257 264 223 214 218 214 바이트

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

온라인으로 사용해보십시오!

ungolfed 버전

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) 숫자의 정수 부분을 반환
  • rem(a,b) a / b의 나머지를 반환
  • cond do end 이것은 많은 명령형 언어의 else if 또는 switch case 절과 같습니다.

설명

get_ring (인덱스)

인덱스의 "링"을 계산합니다.

예 : 1-6의 경우 1, 7-18의 경우 2 등

결과가 수정 된 경우에만 적용됩니다 floor. 후행 숫자는 타일이 링 주위에 얼마나 멀리 있는지 나타냅니다.

inv_get_ring (링)

의 역을 계산합니다 get_ring(index).

ring_base (링)

링에서 첫 번째 타일의 인덱스를 계산합니다.

is_corner (인덱스)

모서리는 외부 링에 3 개의 인접 타일이있는 타일입니다. 가장 안쪽의 링은 전적으로 모서리로 구성됩니다.

예 : 21,24,27,30,33,36

is_last (인덱스)

이 인덱스가 링에서 가장 높은 경우에 해당됩니다.

is_first (인덱스)

이것이 링의 기본 타일 인 경우에 해당됩니다.


2
가장자리 케이스에 대한 수정 사항을 포함하도록 답변을 편집했습니다. :)
Garuno

첫 번째 반복을 통해 골프 버전을 따랐지만 접근 방식을 변경 한 것처럼 보입니다. 현재 골프 버전이 아직 골프 버전과 동일합니까?
John Michael Law

네! 방금 Elixir에서 변수를 인라인으로 선언 할 수 있다는 것을 배웠습니다. 이를 통해 코드 시작 부분에서 람다 함수를 제거 할 수있었습니다. 좀 더 효율적으로하기 위해 변수를 조금 섞었습니다.
가루 노

5

MATL , 47 45 44 43 41 바이트

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

온라인으로 사용해보십시오! 또는 모든 테스트 사례를 확인하십시오 .

보너스로, 코드는 셀 중심의 위치를 ​​추적하는 6 각형 나선을 생성하며, 코드 의 마지막 부분을 수정하여 MATL Online 에서 그래픽으로 볼 수 있습니다 .

설명

일반적인 아이디어이    코드는 먼저 단위 단계를 사용하여 충분히 큰 육각형 나선을 만듭니다. 나선은 셀 중심의 위치를 ​​나타내는 복소수의 벡터로 정의됩니다. 입력 숫자를 사용하여 해당 벡터로 인덱싱하고 절대 차이를 계산하면 표시된 두 셀 사이의 거리가 제공됩니다. 결과가 1 인 경우에만 셀이 인접 해 있습니다. 그러나 부동 소수점 부정확성으로 인해 1과 비교하기 전에 반올림이 필요합니다.

나선 만들기    나선은 두 입력의 합과 같은 많은 "레이어"를 갖습니다. 이것은 필요한 것보다 훨씬 크며 입력 셀이 나선형으로 존재하게합니다.

나선을 만들기 위해 복소수 j 2/3 (여기서 j 는 허수 단위 임)가 먼저 계산됩니다. 이것을 지수 1에서 6까지 올리면 기본적인 변위 세트가 생겨서 그 변위를 따라 가면 육각형이됩니다. 이 육각형은 "닫힌"것을 제외하고 나선의 가장 안쪽 층을 형성합니다. 실제로, 우리는 그 육각형이 마지막 단계에서 "성장"하기를 원한 다음, 나선의 다음 층을 형성하기 위해 두 배의 점 (두 그룹으로 정렬)으로 더 큰 육각형을 추적합니다. 여기 그림을 참조 하십시오 . 다음 레이어는 첫 번째 포인트 (세 그룹으로)의 3 포인트를 갖습니다. 여기를 참조 하십시오 .

이를 위해 기본 세트 (남동 방향을 가리킴)에서 다섯 번째 변위가 "성장"단계로 선택됩니다. 층 k 는 그 단계로 시작하고,이어서 k 회 반복 된 처음 5 개의 기본 단계 ,이어서 k -1 회 반복 된 6 단계 (동쪽 방향)가 이어진다 . 위의 두 그림을 보면 더 명확 해집니다.

모든 레이어를 포함한 결과 벡터는 나선을 추적하는 복잡한 변위를 나타냅니다. 누적 합계는 셀 중심의 실제 좌표를 제공합니다.

마지막으로, 0에 위치한 초기 셀 이이 벡터 의 끝에 첨부 됩니다 . MATL은 모듈 식 1 기반 인덱싱을 사용하고 인덱스 0은 배열의 마지막 항목을 참조하기 때문 입니다.

인접성 테스트    입력 숫자로 지정된 두 개의 셀을 선택하고 좌표를 빼고 절대 값을 반올림 한 후 1과 비교합니다.

주석이 달린 코드

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

설명을 추가해 주시겠습니까?
Shaggy

@Shaggy 일반적인 설명을 추가했습니다. 분명한지 알려주세요 (설명하기 어렵다). 나중에 주석이 달린 코드를 추가하겠습니다
Luis Mendo

2

05AB1E (레거시) , 30 29 27 바이트

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

온라인으로 사용해보십시오!

코드 설명 :

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

수학 설명 :

이 골프를 만드는 데 약 5 시간이 걸렸습니다. 요컨대 나는 입력의 2 차원 그래프를 만들기 시작했으며 X서로 인접 한 곳을 그렸습니다 . 그런 다음 패턴을 찾았습니다. OEIS 와 빙고 에서 검색했습니다 ! 그 순서를 발견 하고 웹 사이트에 제공된 공식을 사용했습니다.


1

C (GCC) , 175 (173) 바이트

버그를 발견 한 Peter Taylor 에게 감사합니다 .

-2 바이트의 ceilingcat 덕분 입니다. 그 ~ 운영자는 계속 내 주요 장님입니다.

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

온라인으로 사용해보십시오!

이 방법은 두 셀의 행과 열을 찾아서 비교하는 데 중점을 둡니다. 이웃의 좌표는 1 이상 차이가 나지 않습니다. 중심에서 바깥쪽으로 이동하면 각 계층에 이전보다 6 개의 셀이 더있는 것을 알 수 있습니다. 즉, 각 레이어 L에서 가장 높은 "인덱스"는 6 * (L * (L-1) * (L-2) ...) 또는 C = 6 * (L 2 + L) / 2 형식입니다. 여기서 C는 "전역"셀 번호입니다. 주변을 뒤섞 으면 L 2 + L-C / 3 = 0이되며, 이는 고등학교 수학 플래시백을 제공합니다. 그로부터 공식 ceil (sqrt (1/4 + C / 3) + 0.5)을 얻습니다. 글로벌 셀 인덱스를 연결하면 셀이 어느 레이어에 있는지 알 수 있습니다.

각 레이어의 첫 번째 셀은 자연스럽게 이전 레이어의 최고 셀보다 하나 더 높으므로 L start = (6 * (L-1) 2 + (L-1)) / 2를 발견하면 3 * (L 2 -L). 이것으로부터 레이어 인덱스 L index = C-L start를 얻습니다 .

다음으로, 각 레이어는 각각 길이 L 인 6 개의 섹션으로 구성되어 있음을 알 수 있습니다. 북동쪽에서 시작하여 시계 반대 방향으로 가면 처음 두 섹션 (1 <= L 인덱스 <= 2 * L)에 대해 L-L 인덱스 에서 열을 얻습니다 . 다음 섹션 L * 2 <L 인덱스 <= L * 3에는 모든 셀이 단일 열 -L을 공유합니다. 두 다음 섹션은 L * 3 <L에있는 인덱스 <= L * 그들의 열 L에 따른 5 개의 인덱스 - L * 4. 그리고 마지막 여섯 번째 섹션은 모든 L. 당사의 상부 경계를 따라 한 스텝 이동 가능 열에 해당 셀을 코드에서 일부 바이트를 저장합니다.

그렇다면 행은 어떻습니까? 코드를 재사용하기 위해 셀 44가 위로 오도록 그리드를 돌립니다. 그런 다음 열과 동일한 논리를 실행하지만 이번에는 결과를 "행"이라고합니다. 물론, 실제로 그리드를 돌리는 대신, 우리는 단지 1/6의 랩을 걸어 다닙니다.


@PeterTaylor 잘 잡아라, 고마워!
gastropner

1

파이썬 3, 150 바이트

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

내 솔루션은 기본적으로 Luis Mendo와 같은 생각을 따릅니다. 더 읽기 쉽게 작성된 코드는 설명이 필요 없습니다.

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. 함수 h는 다음을 수행합니다.
  2. 목록 L에는 각 숫자의 (복잡한) 위치가 포함됩니다.
  3. i 링 번호입니다.
  4. while 루프에서는 반복 할 때마다 새 링이 추가됩니다. 필요한 반지 수를 알아내는 대신 a + b를 포함하기에 충분히 길 때까지 목록을 계속 작성하면됩니다.
  5. 'ring-list' l는 스텝 벡터에 6 개의 len (i) 곱하기 스텝 벡터의 6 개 연결로 구성되며, 스텝 벡터는 1j ** (2/3)의 거듭 제곱입니다. 범위는 0에서 시작하지 않고 4에서 시작하여 전체 그리드가 회전합니다. 이것은 내가 할 수 있습니다 :
  6. l[0]+=1 6 번째 줄에서, 이것은 한 링에서 다음 링으로의 단계입니다.
  7. L+=l 전체 목록과 링 목록을 연결합니다.
  8. 목록 L에는 단계 벡터 만 포함되며, 위치 벡터를 얻기 위해서는 여전히 합산되어야합니다. 여기서 깔끔한 특징은 슬라이스 를 가장 낮은 숫자에서 가장 높은 숫자까지 합산하여 거리를 얻을 수 있다는 것입니다! 반올림 오류로 인해 결과는 정확히 1이 아니므로 .9 <... <1.1입니다. 흥미롭게도 h(0,0)빈 목록의 합계가 0이기 때문에 제로 경우 또는 h (0,1)이 암시 적으로 처리됩니다. a<b즉, 인수의 순서가 늘어날 것이라고 확신 할 수 있다면 으로 대체 L[min(a,b):max(a,b)]하여 14 바이트를 더 줄일 수 L[a:b]는 있지만 아아!

추신 : 나는 이것이 오래된 도전이라는 것을 몰랐고, 며칠 전에 최고로 나타 났으며 그 이후로 계속 잔소리했습니다.)


이것은 좋은 답변입니다! 늦은 답변에 대해 걱정하지 마십시오. 여기 PPCG에 관한 문제는 없습니다.
Rɪᴋᴇʀ

0

매쓰, 111 (105) 104 바이트

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&

설명:

r=Floor[(1+Sqrt[(4#-1)/3])/2]&r입력을 받는 함수 를 정의하고 #셀 0까지의 거리 (셀 수)를 계산합니다. 각 거리 / 링의 마지막 셀에있는 패턴을 활용하여이를 수행합니다. 0 = 3 (0 ^ 2 + 0), 6 = 3 (1 ^ 2 + 1), 18 = 3 (2 ^ 2 + 2), 36 = 3 (3 ^ 2 + 3) ...... 해당 패턴의 수식을 반전시킵니다. 셀 0의 경우 실제로 (1/2) + i * (sqrt (3) / 6) 의 바닥을 차지하며 , 구성 요소별로 계산하여 0 + 0 * i = 0 을 얻습니다 .

으로 r정의 된 r@#셀에 대한 고리 #(다른 함수의 정의 내부). #+3r@#-3(r@#)^2&코드에 정확하게 표시되지 않지만 셀 수를 가져와 다음 내부 링에서 가장 많은 수의 셀을 뺀 다음 "현재 링의 어떤 셀이 무엇입니까?"라는 질문에 대한 답변을 제공합니다. 예를 들어, 셀 9는 링 2의 세 번째 셀이므로 r[9]2를 #+3r@#-3(r@#)^2&[9]출력하고 3을 출력합니다.

IS가 찾아 그것을 사용 위에 우리는 기능을 수행 할 수있는 극 각 해당 셀의에서 반 시계 방향으로 각도 "셀에 0, 셀 (17), 전지 (58)"선. 모든 링의 마지막 셀은 항상 Pi / 6 각도에 있으며 Pi / (3 * ring_number) 단위로 링 주위를 돌고 있습니다. 따라서 이론적으로 Pi / 6 + (which_cell_of_the_current_ring) * Pi / (3 * ring_number)와 같은 것을 계산해야합니다. 그러나 그림의 회전은 아무런 영향을 미치지 않으므로 Pi / 6 부분을 버릴 수 있습니다 (6 바이트 절약). 이것을 이전 공식과 결합하고 단순화하면Pi(#/(3r@#)+1-r@#)&

불행히도, 링 번호가 0이므로 셀 0에 대해 정의되지 않았 으므로이 문제를 해결해야합니다. 자연스러운 해결책은 다음과 같습니다 t=If[#==0,0,Pi(#/(3r@#)+1-r@#)]&. 그러나 우리는 셀 0의 각도에 신경 쓰지 않고 r@#반복 되기 때문에 실제로 여기에 바이트를 저장할 수 있습니다t=Limit[Pi(#/(3x)+1-x),x->r@#]&

링 번호와 각도가 생겼으므로 셀 (중심)의 위치를 ​​찾아서 인접성을 테스트 할 수 있습니다. 고리가 육각형이기 때문에 실제 위치를 찾는 것은 성가신 일이지만, 고리를 완벽한 원이라고 가정하면 고리 번호를 셀 0의 중심까지의 거리로 취급 할 수 있습니다. 닫기. 복소수극좌표 형식을 사용하여 간단한 평면 함수로 복잡한 평면 에서이 대략적인 위치를 나타낼 수 있습니다 .p = r@#*Exp[I*t@#] &;

복소수 평면에서 두 복소수 사이의 거리는 차이의 절대 값 에 의해 주어진 다음 근사값의 오차를 처리하기 위해 결과를 반올림하고 이것이 1인지 확인합니다. 이 작품은 이름이 없지만입니다 Round@Abs[p@#-p@#2]==1&.


Wolfram Cloud 샌드 박스 에서 다음과 같은 코드를 붙여 넣고 Gear- > "셀 평가"를 클릭하거나 Shift + Enter 또는 숫자 키패드 Enter를 눌러 온라인으로 시도 할 수 있습니다 .

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]

또는 모든 테스트 사례의 경우 :

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}}]]&
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.