Mathematica, 111 105 104 bytes
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&
Explanation:
r=Floor[(1+Sqrt[(4#-1)/3])/2]&
defines a function r
which takes input #
and calculates the distance (in number of cells) to cell 0. It does this by exploiting the pattern in the last cells of each distance/ring: 0=3(0^2+0), 6=3(1^2+1), 18=3(2^2+2), 36=3(3^2+3),... and inverting the formula for that pattern. Note that for cell 0, it actually takes the floor of (1/2)+i *(sqrt(3)/6), which it calculates component-wise to get 0+0 * i = 0.
With r
defined, r@#
is the ring for cell #
(inside the definition of another function). #+3r@#-3(r@#)^2&
does not appear in the code exactly, but it takes the number of a cell and subtracts the highest number of a cell in the next inner ring, so that it gives the answer to the question "which cell of the current ring is this?" For example, cell 9 is the 3rd cell of ring 2, so r[9]
would output 2 and #+3r@#-3(r@#)^2&[9]
would output 3.
What we can do with the function above is use it to find the polar angle, the counter-clockwise angle from the "cell 0, cell 17, cell 58" ray to the cell in question. The last cell of every ring is always at an angle Pi/6, and we go around a ring in increments of Pi/(3*ring_number). So, in theory, we need to calculate something like Pi/6+(which_cell_of_the_current_ring)*Pi/(3*ring_number). However, the rotation of the picture doesn't affect anything, so we can discard the Pi/6 part (to save 6 bytes). Combining this with the previous formula and simplifying, we get Pi(#/(3r@#)+1-r@#)&
Unfortunately, this is undefined for cell 0 since its ring number is 0, so we need to get around this. A natural solution would be something like t=If[#==0,0,Pi(#/(3r@#)+1-r@#)]&
. But since we don't care about the angle for cell 0 and because r@#
is repeated, we can actually save a byte here with t=Limit[Pi(#/(3x)+1-x),x->r@#]&
Now that we have the ring number and the angle, we can to find the position of a cell (center) so we can test for adjacency. Finding the actual position is annoying because the rings are hexagonal, but we can simply pretend the rings are perfect circles so that we treat ring number as the distance to the center of cell 0. This won't be a problem since the approximation is pretty close. Using the polar form of a complex number, we can represent this approximate position in the complex plane with a simple function: p = r@#*Exp[I*t@#] &;
The distance between two complex numbers on the complex plane is given by the absolute value of their difference, and then we can round the result to take care of any errors from the approximation, and check if this is equal to 1. The function that finally does this work doesn't have a name, but is Round@Abs[p@#-p@#2]==1&
.
You can try it online in the Wolfram Cloud sandbox by pasting code like the following and clicking Gear->"Evaluate cell" or hitting Shift+Enter or the 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]
Or for all test cases:
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}}]]&