Lục giác kề


28

Ví dụ hình lục giác xoắn ốc

Hình trên hiển thị một lưới lục giác hình lục giác. Mỗi ô trong lưới được gán một chỉ mục, bắt đầu từ trung tâm và xoắn ốc ngược chiều kim đồng hồ xung quanh như được hiển thị. Lưu ý rằng lưới sẽ tiếp tục vô thời hạn - hình trên chỉ đơn giản là phần đầu tiên. Hình lục giác tiếp theo sẽ tiếp giáp với 60 và 37.

Nhiệm vụ của bạn là xác định xem hai ô đã cho trên lưới này có liền kề nhau không.

Viết chương trình hoặc hàm, đưa ra hai chỉ mục ô, in / trả về giá trị trung thực nếu hai ô liền kề và giá trị falsey nếu không.

Nếu không bị giới hạn bởi các lý do thực tế, về mặt lý thuyết, mã của bạn sẽ hoạt động cho mọi kích thước đầu vào.

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

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

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

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

Đây là vì vậy câu trả lời ngắn nhất bằng byte sẽ thắng. Giải thích, ngay cả đối với các ngôn ngữ không bí truyền, được khuyến khích.

Câu trả lời:


7

Elixir , 263 257 264 223 214 218 214 byte

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

Hãy thử trực tuyến!

phiên bản vô văn hóa

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) Trả về phần nguyên của số
  • rem(a,b) Trả về phần còn lại của a / b
  • cond do end Điều này tương đương với khác nếu hoặc chuyển đổi mệnh đề trường hợp trong nhiều ngôn ngữ mệnh lệnh

Giải trình

get_ring (chỉ mục)

Tính "vòng" của chỉ số.

Ví dụ: 1 cho 1-6, 2 cho 7-18, v.v.

Điều này chỉ áp dụng nếu kết quả là floored. Các chữ số Trailing biểu thị khoảng cách mà gạch xung quanh vòng.

inv_get_ring (đổ chuông)

Tính toán nghịch đảo của get_ring(index).

ring_base (vòng)

Tính chỉ số của ô đầu tiên trong vòng.

is_c Corner (chỉ mục)

Các góc là các gạch có ba gạch phụ ở vòng ngoài. Các vòng trong cùng bao gồm hoàn toàn các góc.

Ví dụ: 21,24,27,30,33,36

is_last (chỉ mục)

Là đúng nếu chỉ số này là cao nhất trong vòng của nó.

is_first (chỉ mục)

Là đúng nếu đây là gạch cơ sở của vòng.


2
Tôi đã chỉnh sửa câu trả lời để bao gồm sửa lỗi cho trường hợp cạnh :)
Garuno

Tôi đã theo dõi phiên bản chơi gôn của bạn qua lần đầu tiên qua các lần lặp nhưng sau đó có vẻ như bạn đã thay đổi cách tiếp cận của mình. Phiên bản chơi gôn hiện tại của bạn có còn tương đương với phiên bản không có người lái không?
Luật John Michael

Đúng vậy Tôi vừa học được rằng bạn có thể khai báo các biến nội tuyến trong Elixir. Điều này đã cho tôi khả năng loại bỏ các hàm lambda ở đầu mã. Tôi chỉ xáo trộn các biến xung quanh một chút, để làm cho nó hiệu quả hơn.
Garuno

5

MATL , 47 45 44 43 41 byte

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

Hãy thử trực tuyến! Hoặc xác minh tất cả các trường hợp thử nghiệm .

Như một phần thưởng, mã tạo ra một hình xoắn ốc lục giác theo dõi vị trí của các trung tâm tế bào, có thể nhìn thấy bằng đồ họa tại MATL Online bằng cách sửa đổi phần cuối của mã.

Giải trình

Ý tưởng chung    Mã đầu tiên xây dựng một hình lục giác đủ lớn với bước đơn vị. Hình xoắn ốc được định nghĩa là một vectơ của các số phức biểu thị vị trí của các trung tâm tế bào. Lập chỉ mục vào vectơ đó với các số đầu vào và tính toán sự khác biệt tuyệt đối cho khoảng cách giữa hai ô được chỉ định. Các ô liền kề khi và chỉ khi kết quả là 1. Tuy nhiên, do không chính xác điểm nổi, làm tròn là cần thiết trước khi so sánh với 1.

Xây dựng hình xoắn ốc    Hình xoắn ốc sẽ có một số "lớp" bằng tổng của hai đầu vào. Đây là (nhiều) lớn hơn mức cần thiết và đảm bảo rằng các ô đầu vào sẽ có mặt trong vòng xoắn ốc.

Để xây dựng hình xoắn ốc, số phức j 2/3 (trong đó j là đơn vị tưởng tượng) được tính toán đầu tiên. Việc nâng mức này lên số mũ từ 1 đến 6 sẽ tạo ra một tập hợp các chuyển vị cơ bản, sao cho theo các chuyển vị đó theo thứ tự sẽ theo dõi một hình lục giác. Hình lục giác này sẽ tạo thành lớp trong cùng của xoắn ốc, ngoại trừ việc nó sẽ bị "đóng". Trên thực tế, chúng tôi muốn hình lục giác đó "phát triển" ở bước cuối cùng và sau đó chúng tôi theo dõi một hình lục giác lớn hơn, với số điểm gấp đôi (được xếp theo nhóm hai), để tạo thành lớp tiếp theo của hình xoắn ốc; xem hình minh họa ở đây . Lớp tiếp theo sẽ có ba lần nhiều điểm đầu tiên (trong nhóm ba); thấy ở đây .

Để làm điều này, sự dịch chuyển thứ năm từ tập cơ bản (chỉ theo hướng đông nam) được chọn là bước "phát triển". Lớp k bắt đầu với bước đó, tiếp theo là năm bước cơ bản đầu tiên được lặp lại k lần, tiếp theo là bước thứ sáu (hướng đông) lặp lại k −1 lần. Điều này hy vọng sẽ trở nên rõ ràng hơn bằng cách nhìn vào hai con số được liên kết ở trên.

Vectơ kết quả, bao gồm tất cả các lớp, đại diện cho các chuyển vị phức tạp sẽ theo dõi đường xoắn ốc. Tổng tích lũy cho tọa độ thực của các trung tâm tế bào.

Cuối cùng, ô ban đầu, nằm ở 0, được gắn vào cuối của vectơ này. Điều này là do MATL sử dụng lập chỉ mục dựa trên mô-đun 1 và chỉ mục 0 đề cập đến mục cuối cùng của một mảng.

Kiểm tra tính phụ thuộc    Hai ô được cung cấp bởi các số đầu vào được chọn, tọa độ của chúng bị trừ và giá trị tuyệt đối được làm tròn và so sánh với 1.

Mã nhận xét

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

Bạn có thể thêm một lời giải thích?
Xù xì

@Shaggy Tôi thêm một lời giải thích chung. Hãy cho tôi biết nếu nó rõ ràng (thật khó để giải thích). Tôi sẽ thêm mã nhận xét sau
Luis Mendo

2

05AB1E (di sản) , 30 29 27 byte

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

Hãy thử trực tuyến!

Giải thích về mã:

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

Giải thích về toán học:

Tôi "lãng phí" khoảng 5 giờ để chơi gôn này. Nói tóm lại, tôi bắt đầu tạo một đồ thị 2d của các đầu vào và vẽ Xnơi chúng nằm kề nhau. Sau đó, tôi tìm thấy một mô hình. Tôi đã tìm kiếm nó trên OEIS và bingo! Tôi tìm thấy trình tự đó và tôi đã sử dụng công thức được đưa ra trên trang web.


1

C (gcc) , 175 173 byte

Cảm ơn Peter Taylor đã bắt được một lỗi.

Nhờ trần nhà cho -2 byte. Đó ~ toán tử tiếp tục là điểm mù chính của tôi.

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

Hãy thử trực tuyến!

Cách tiếp cận này tập trung vào việc tìm hàng và cột của hai ô và so sánh chúng; bất kỳ hàng xóm nào cũng không thể có tọa độ tương ứng khác nhau hơn 1. Di chuyển từ tâm ra ngoài, chúng tôi quan sát thấy mỗi lớp có nhiều ô hơn 6 ô trước đó. Điều này có nghĩa là "chỉ số" cao nhất trong mỗi lớp L ở dạng 6 * (L * (L - 1) * (L - 2) ...) hoặc C = 6 * (L 2 + L) / 2 , trong đó C là số ô "toàn cầu". Xáo trộn mọi thứ xung quanh, chúng ta nhận được L 2 + L - C / 3 = 0, điều này mang lại những hồi tưởng toán học ở trường trung học. Từ đó, chúng ta có được công thức ceil (sqrt (1/4 + C / 3) + 0.5). Cắm một chỉ mục ô toàn cầu vào nó, chúng ta sẽ nhận được lớp nào của ô.

Vì ô đầu tiên trong mỗi lớp tự nhiên cao hơn lớp cao nhất của lớp trước, chúng tôi tìm thấy L start = (6 * (L - 1) 2 + (L - 1)) / 2, đơn giản hóa thành 3 * (L 2 - L). Từ đó ta lấy chỉ số lớp L index = C - L bắt đầu .

Tiếp theo, chúng ta thấy rằng mỗi lớp bao gồm sáu phần, mỗi phần dài L. Bắt đầu từ phía đông bắc và đi ngược chiều kim đồng hồ, chúng ta thấy rằng trong hai phần đầu tiên (1 <= L index <= 2 * L) , chúng tôi nhận được cột từ L - L chỉ số . Phần tiếp theo L * 2 <L index <= L * 3 có tất cả các ô chia sẻ một cột -L. Hai phần tiếp theo là L * 3 <L index <= L * 5 với các cột theo chỉ số L - L * 4. Và cuối cùng, phần thứ sáu đều có các ô trên cột L. Chúng ta có thể dịch chuyển các giới hạn trên một bước dọc theo để lưu một số byte trong mã.

Vậy còn hàng thì sao? Để sử dụng lại mã, chúng ta xoay lưới để ô 44 thẳng lên. Sau đó, chúng tôi chạy logic tương tự như cho các cột nhưng gọi kết quả là "hàng" trong khoảng thời gian này. Tất nhiên, thay vì thực sự xoay lưới, chúng ta chỉ cần đi 1/6 vòng quanh nó.


@PeterTaylor Bắt tốt, cảm ơn!
dạ dày

1

Python 3, 150 byte

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

Giải pháp của tôi về cơ bản theo cùng một dòng suy nghĩ như của Luis Mendo ở trên. Nếu được viết dễ đọc hơn, mã này khá tự giải thích:

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. chức năng hthực hiện như sau:
  2. Danh sách L sẽ chứa các vị trí (phức tạp) của mỗi số.
  3. i là số vòng.
  4. Trong vòng lặp while, một vòng mới được thêm vào mỗi lần lặp. Thay vì tìm ra chúng ta cần bao nhiêu chiếc nhẫn, chúng ta chỉ cần tiếp tục xây dựng danh sách cho đến khi đủ dài để chứa a + b, thì nó chắc chắn đủ dài để chứa một trong số chúng.
  5. 'danh sách vòng' llà sự kết hợp của 6 danh sách len (i) nhân với vectơ bước, trong đó vectơ bước là 1j ** (2/3) với một số công suất. Phạm vi không bắt đầu từ 0 mà ở 4, điều này gây ra một vòng quay của toàn bộ lưới. Điều này cho phép tôi làm:
  6. l[0]+=1 trong dòng 6, đó là bước từ vòng này sang vòng tiếp theo.
  7. L+=l nối các danh sách đầy đủ và danh sách vòng.
  8. Danh sách L chỉ chứa các vectơ bước, vẫn phải được tổng hợp (tích hợp) để có được một vị trí. Một tính năng gọn gàng ở đây là chúng ta có thể tổng hợp các lát cắt từ số thấp nhất đến cao nhất để có được khoảng cách của chúng! Do lỗi vòng, kết quả sẽ không chính xác là 1, do đó, .9 <... <1.1. Thật thú vị, trường hợp zero h(0,0)hoặc h (0,1) được xử lý ngầm, bởi vì tổng của một danh sách trống bằng không. Nếu tôi có thể chắc chắn rằng a<b, tức là các đối số sẽ theo thứ tự tăng dần, tôi có thể loại bỏ 14 byte khác bằng cách thay thế L[min(a,b):max(a,b)]bằng L[a:b], nhưng than ôi!

Tái bút: Tôi không biết đây là một thử thách cũ, nó đã xuất hiện trên đỉnh vài ngày trước và cứ cằn nhằn tôi kể từ đó :)


Đây là một câu trả lời tuyệt vời! Đừng lo lắng về câu trả lời muộn, chúng tôi thực sự không có bất kỳ vấn đề nào với điều đó ở đây trên PPCG.
Rɪᴋᴇʀ

0

Toán học, 111 105 104 byte

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&

Giải trình:

r=Floor[(1+Sqrt[(4#-1)/3])/2]&định nghĩa một hàm rlấy đầu vào #và tính khoảng cách (tính theo số ô) đến ô 0. Nó thực hiện điều này bằng cách khai thác mẫu trong các ô cuối cùng của mỗi khoảng cách / vòng: 0 = 3 (0 ^ 2 + 0), 6 = 3 (1 ^ 2 + 1), 18 = 3 (2 ^ 2 + 2), 36 = 3 (3 ^ 2 + 3), ... và đảo ngược công thức cho mẫu đó. Lưu ý rằng đối với ô 0, nó thực sự lấy sàn của (1/2) + i * (sqrt (3) / 6), nó tính toán thành phần khôn ngoan để nhận 0 + 0 * i = 0.

Với rđịnh nghĩa, r@#là vòng cho ô #(bên trong định nghĩa của hàm khác). #+3r@#-3(r@#)^2&không xuất hiện chính xác trong mã, nhưng nó lấy số ô và trừ đi số ô cao nhất trong vòng bên trong tiếp theo, để nó đưa ra câu trả lời cho câu hỏi "ô nào của vòng hiện tại là đây?" Ví dụ, ô 9 là ô thứ 3 của vòng 2, do đó r[9]sẽ xuất ra 2 và #+3r@#-3(r@#)^2&[9]sẽ xuất 3.

Những gì chúng ta có thể làm với chức năng trên là sử dụng nó để tìm góc cực , góc ngược chiều kim đồng hồ từ tia "ô 0, ô 17, ô 58" đến ô đang xét. Ô cuối cùng của mỗi vòng luôn nằm ở góc Pi / 6 và chúng ta đi xung quanh một vòng theo số gia của Pi / (3 * ring_number). Vì vậy, về mặt lý thuyết, chúng ta cần tính toán một cái gì đó như Pi / 6 + (which_cell_of_the_civerse_ring) * Pi / (3 * ring_number). Tuy nhiên, xoay của hình ảnh không ảnh hưởng đến bất cứ điều gì, vì vậy chúng tôi có thể loại bỏ phần Pi / 6 (để lưu 6 byte). Kết hợp điều này với công thức trước và đơn giản hóa, chúng ta có đượcPi(#/(3r@#)+1-r@#)&

Thật không may, điều này không được xác định cho ô 0 vì số vòng của nó là 0, vì vậy chúng ta cần phải khắc phục điều này. Một giải pháp tự nhiên sẽ là một cái gì đó như t=If[#==0,0,Pi(#/(3r@#)+1-r@#)]&. Nhưng vì chúng ta không quan tâm đến góc của ô 0 và vì r@#được lặp lại, nên chúng ta thực sự có thể lưu một byte ở đây vớit=Limit[Pi(#/(3x)+1-x),x->r@#]&

Bây giờ chúng ta có số vòng và góc, chúng ta có thể tìm vị trí của một ô (ở giữa) để chúng ta có thể kiểm tra độ kề. Việc tìm vị trí thực tế rất khó chịu vì các vòng tròn là hình lục giác, nhưng chúng ta chỉ có thể giả vờ các vòng là các vòng tròn hoàn hảo để chúng ta coi số vòng là khoảng cách đến trung tâm của ô 0. Đây không phải là vấn đề vì phép tính gần đúng là khá gần. Sử dụng dạng cực của một số phức , chúng ta có thể biểu diễn vị trí gần đúng này trong mặt phẳng phức với một hàm đơn giản:p = r@#*Exp[I*t@#] &;

Khoảng cách giữa hai số phức trên mặt phẳng phức được tính bằng giá trị tuyệt đối của chênh lệch của chúng, và sau đó chúng ta có thể làm tròn kết quả để xử lý bất kỳ lỗi nào từ phép tính gần đúng và kiểm tra xem nó có bằng 1. Hàm cuối cùng không công việc này không có tên, nhưng là Round@Abs[p@#-p@#2]==1&.


Bạn có thể dùng thử trực tuyến trong hộp cát Wolfram Cloud bằng cách dán mã như sau và nhấp vào Gear -> "Đánh giá ô" hoặc nhấn Shift + Enter hoặc numpad 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]

Hoặc cho tất cả các trường hợp thử nghiệm:

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}}]]&
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.