161 153 148 146 bytes
Try it online!
Golfed version of the original 175-byte concept. Now competing with the golfing languages!
j=k/10. Introduced new variable
b are now integers (not normalised by dividing by
m=n*1.0, with other values scaled up by
Conditionals used for selection instead of arrays.
d was revised
true/false instead of
0/1, then eliminated completely.
e<0? (used twice) is overall shorter than
d ? because it doesn't require whitespace, or prior definition of
Instead of using pythagoras (squaring then square root) to calculate scale factor
z and take
abs of the result. This allowed
z to be calculated on the same line as the scale factor calculation (but means the output is now
~0**k to allow deletion of parentheses. Similarly redistributed calculation of
2i instead of
1i as previously allows movement of
2*r*c**k and deletion of parentheses.)
 around output. This alters readability because it prints each point over 2 lines instead of 1, but saves 2 bytes.
Ruby, 175 bytes
first working version
Try it online!
A function that takes an argument
n and prints the vertices in the format
[z,x+yi]. One pair of opposite vertices is aligned with the
z axis; these vertices are printed last. The code generates each vertex exactly once with no duplicates, per OP's comment in the post.
According to https://mathworld.wolfram.com/RegularIcosahedron.html
A construction for a icosahedron... places the end vertices at (0,0,+/-1) and the central vertices around two staggered circles of radii 2/sqrt(5) and heights +/- 1/sqrt(5)
This code produces the
zcoordinates of the icosahedron at a scaled up size of
0,0,sqrt(5) for the end vertices, which puts the other vertices at
z=+/-1. For calculation of the x and y coordinates, the radius of the circle is conveniently set to 1, but the coordinates are doubled for compatability with the z coordinates prior to normalization.
The icosahedron is split into 10 identical diamonds as below. We include only the points marked with an
X because the points marked with
O are included as part of the adjacent diamond. We do however have to include the poles (marked as
The diamond is folded at the join of the two triangles. Looking down the
z axis at the
x+yi plane, the polar apex is at
0+0i, and the other apex is at
1+0i. The right vertex is at a 1/10th rotation,
c=i**0.4 = 0.809+0.588i. The left vertex is at the conjugate,
0.809-0.588i. As the absolute value of
c is 1, the conjugate is conveniently generated by
? x+yi=0 z=sqrt(5)
/ \ / \
O X X
x+yi / \ / \ / \ x+yi
=1/c O---X---X---X =c=i**0.4 z=1
=0.809 \ / \ / \ / =0.809
-0.588i O X X +0.588i Note: x,y coordinates at half
\ / \ / the scale of z coordinates
O X (they are doubled before normalization)
O x+yi=1 z=-1
We work through the
n*n points in the diamond with increments in the value of
j. we start at
[r=x+yi=c,z=1], with increasing value of
b=j%n moving diagonally towards the bottom corner and
a=j/n moving diagonally towards the top corner. different vectors (selected by
d=a>b) must be added to the starting point for the upper and lower triangle.
Upper triangle a>b a*(0-c)+b*(1/c-0) (a-b)*(5**0.5-1)
Lower triangle a<=b b*(1-c)+a*(1/c-1) (a-b)*2
For each value of
j we generate 10 images by 1/10 rotation of the value
r=x+yi by multiplying by
c**k and flipping the
z value by multiplying by
-1**k (due to priority of operators in Ruby, this is represented as
n*n*10 iterations, we have covered all points up to
a=b=n-1. It remains to add the polar vertices. This just requires another 2 iterations where the value of
Finally, the last line normalizes the points to a sphere and outputs them.