六角邻接


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

这是因此最短的答案以字节为单位。鼓励即使是非深奥的语言也要进行解释。

Answers:


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

在线尝试!

非高尔夫版本

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(index)

计算索引的“环”。

例如:1代表1-6,2代表7-18,依此类推。

仅当结果为floored时适用。 尾随数字表示该磁贴在环上的距离。

inv_get_ring(ring)

计算的逆get_ring(index)

ring_base(ring)

计算环中第一个图块的索引。

is_corner(索引)

角是在外环中具有三个相邻瓷砖的瓷砖。最里面的环完全由角组成。

示例:21,24,27,30,33,36

is_last(索引)

如果此索引在其环中最高,则为true。

is_first(索引)

如果这是指环的基块,则为true。


2
我已经编辑了答案,以包括对
极端

从头到尾,我一直关注您的高尔夫球版本,但随后您似乎改变了自己的方法。您当前的高尔夫版本是否仍然与非高尔夫版本相同?
约翰·迈克尔·劳

是的!我刚刚了解到可以在Elixir中内联声明变量。这使我能够在代码开头摆脱lambda函数。我只是对变量进行了一些调整,以使其更加高效。
Garuno

5

MATL47 45 44 43 41字节

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

在线尝试!验证所有测试用例

另外,该代码会生成一个六边形螺旋,以跟踪细胞中心的位置,可以通过修改代码的最后一部分在MATL Online上以图形方式看到。

说明

总体思路    该代码首先构建一个具有单位步长的足够大的六角形螺旋。螺旋被定义为代表细胞中心位置的复数向量。用输入数字索引到该向量中并计算绝对差,即可得出两个所示单元之间的距离。当且仅当结果为1时,单元格才是相邻的。但是,由于浮点数不准确,在与1比较之前,必须舍入。

建立螺旋线螺旋    线的“层数”等于两个输入的总和。这比必要的要大得多,并确保输入单元以螺旋形式存在。

为了建立螺旋,首先要计算复数j 2/3(其中j是虚数单位)。将其提高到指数1至6可得到一组基本位移,以使按照这些位移顺序可绘制出六边形。该六边形将形成螺旋的最内层,除非它是“封闭的”。实际上,我们希望六边形在最后一步“增长”,然后追踪一个更大的六边形,其点数是两倍(以两个为一组对齐),以形成螺旋的下一层。请参阅此处的插图。下一层的点数是第一层的三倍(每三点一组);看这里

为此,选择距基本位置的第五个位移(指向东南方向)作为“增长”步骤。层k从该步骤开始,然后是重复前k次的前五个基本步骤,然后是重复了k -1次的第六步(向东)。通过查看上面链接的两个数字,希望这将变得更加清晰。

所得的矢量(包括所有层)表示将跟踪螺旋的复杂位移。累计和给出了单元中心的实际坐标。

最后,位于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我添加了一般解释。让我知道是否清楚(很难解释)。我将在以后添加注释的代码
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个小时来打高尔夫球。简而言之,我开始制作输入的二维图,并绘制X它们彼此相邻的位置。然后我找到了一个模式。我在OEIS和Bingo 上搜索了它!我发现那个顺序并使用了网站上给出的公式。


1

C(gcc)175个 173字节

感谢Peter Taylor捕获错误。

感谢ceilingcat的-2个字节。那个〜运算符仍然是我的主要盲点。

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。从东北开始,然后逆时针旋转,我们看到前两个部分(1 <= L index <= 2 * L) ,我们从L-L 索引得到列。下一节L * 2 <L 索引 <= L * 3使所有单元格共享一个列-L。接下来的两个部分是L * 3 <L 索引 <= L * 5,其列根据L索引 -L *4。最后,第六部分的单元格都在L列上。我们可以将上限沿一个方向移动在代码中保存一些字节。

那行呢?为了重用代码,我们旋转网格,以使单元格44笔直。然后,我们运行与列相同的逻辑,但是这次将结果称为“行”。当然,我们实际上并没有转动网格,而只是绕网格走了1/6圈。


@PeterTaylor很好,谢谢!
gastropner

1

Python 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. “环形列表” l是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)或h(0,1)被隐式处理,因为空列表的总和为零。如果我可以确信a<b,即论证会来递增的顺序,我可以通过更换剃去另外14个字节L[min(a,b):max(a,b)]L[a:b],但很可惜!

PS:我不知道这是一个如此古老的挑战,它在几天前就登上了榜首,并且从那以后一直在na我:)


这是一个很好的答案!不用担心答案太晚,我们在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。

具有rdefine的r@#是单元格的环#(在另一个函数的定义内部)。#+3r@#-3(r@#)^2&不会确切地出现在代码中,但是它需要一个单元格的数目并减去下一个内环中单元格的最高数目,因此它给出了以下问题的答案:“当前环是哪个单元格?” 例如,单元9是环2的第三个单元,因此r[9]将输出2和#+3r@#-3(r@#)^2&[9]输出3。

我们可以使用上面的函数来找到极角从“单元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}}]]&
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.