12
\$\begingroup\$

I have a weakness for 3d nets which when cut out and folded allow you to make 3d shapes out of paper or card. The task is simple, written the shortest program you can that draws nets for the 13 Archimedean solids. The output should be an image file in any sensible format (png, jpg).

All thirteen shapes are described at http://en.wikipedia.org/wiki/Archimedean_solid and in the following table taken from there.

enter image description here

Input: An integer from 1 to 13. Assume the shapes are numbered exactly as in the table above so that the "truncated tetrahedron" is number 1 and the "snub dodecahedron" is number 13.

Output: An image file containing the net for that shape. Just the outline including the internal lines is OK. There is no need to fill it in with colors

You can use any programming language you like as well as any library that was not made especially for this competition. Both should be available freely however (in both senses) online.

I will accept the answer with the smallest number of characters in exactly one week's time. Answers will be accepted whenever they come.

(No) Winner yet. Sadly no valid entrants. Maybe it is too hard?

\$\endgroup\$
3
  • \$\begingroup\$ Maybe do away with the time-limit altogether? What if somebody finds this a year from now. Do you want them not to try?...Might've been better to do the Platonic first, wait, then the hard one. You may have divided the interest. For me personally (all of this is extrapolation), when I saw two similar ones, I kind of withdrew from it, feeling I didn't have the time to really look at both and plan out how to solve both. And I wouldn't want to do it any other way....On the other hand, others here have had difficulty with Part-2 challenges. See the Minsky Register Machine ones. Maybe it's not you. \$\endgroup\$ Commented Feb 18, 2013 at 0:15
  • \$\begingroup\$ @luserdroog Thanks. Question edited. I should maybe add that I have emailed the answer to the related question around lots of people who love it! FWIW. \$\endgroup\$ Commented Feb 20, 2013 at 16:16
  • \$\begingroup\$ I don't think it's hard to do, but to golf it requires several hours of thinking and experimenting because there are many possible nets for each polyhedron and they won't compress equally well. \$\endgroup\$ Commented Mar 2, 2013 at 12:58

3 Answers 3

10
\$\begingroup\$

Java, 1552

import java.awt.*;import java.awt.image.*;import java.io.*;import javax.imageio.*;class A{public static void main(String[]x)throws Exception{String[]a={"33623368356:356;66","33413341334535463547354735473444","33823382338:3586338>358>358>358?88","66456:466:466845684668466766","334144453546354635474746464646464647354634463446344744","88456:466:466:4668458<468<468<468:456846684668466788","33343535353231333535313133353447353434353534313133353447353545343535313133353447353545343444","33513351335233593554335433593554335935543359355433593559355835593559355935593455","33:233:233:433:B35:833:833:B35:833:B35:833:B35:833:B35:B35:833:B35:B35:B35:B35:C::","66566:576:57696869576969586969586:586969576969586857685868586766","334155453546354635463547594658465846584658473546354634463546344635463446354634463547584657465746574657473546344634463446344755","::456:466:466:466:466845:@46:@46:@46:@46:>4568466:4668466:4668466:4668466:4668466845:>46:>46:>46:>46:<45684668466846684667::","333531333434343132333434353531313335343434323232323334343435353231333133343556343434313233323335345935353532313331313132333233353535343557343133343556343434355934353535593432333234355935323335345935323335345935323335345935343459313334353455"};BufferedImage m=new BufferedImage(1300,1300,1);Graphics2D g=m.createGraphics();g.translate(500,500);String s=a[Integer.valueOf(x[0])-1];int f=1,i=0,n,t;while(i<s.length()){n=s.charAt(i++)-48;t=s.charAt(i++);while(t-->48){g.drawLine(0,0,20,0);g.translate(20,0);g.rotate(f*Math.PI*2/n);}f=-f;}ImageIO.write(m,"png",new File("o.png"));}} 

Ungolfed:

import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.io.File; import javax.imageio.ImageIO; public class A { static int f = 1; static Graphics2D g; static void fixtrans() { double[] m = new double[6]; g.getTransform().getMatrix(m); for (int i = 0; i < 6; ++i) { if (Math.abs(m[i] - Math.round(m[i])) < 1e-5) { m[i] = Math.round(m[i]); } } g.setTransform(new AffineTransform(m)); } static void d(String s) { for (int i = 0; i < s.length();) { int n = s.charAt(i++) - '0'; int t = s.charAt(i++) - '0'; for (int j = 0; j < t; ++j) { g.drawLine(0, 0, 20, 0); g.translate(20, 0); g.rotate(f * Math.PI * 2 / n); fixtrans(); // optional, straightens some lines } f = -f; } } public static void main(String[] args) throws Exception { String[] a = { "33623368356:356;66", "33413341334535463547354735473444", "33823382338:3586338>358>358>358?88", "66456:466:466845684668466766", "334144453546354635474746464646464647354634463446344744", "88456:466:466:4668458<468<468<468:456846684668466788", "33343535353231333535313133353447353434353534313133353447353545343535313133353447353545343444", "33513351335233593554335433593554335935543359355433593559355835593559355935593455", "33:233:233:433:B35:833:833:B35:833:B35:833:B35:833:B35:B35:833:B35:B35:B35:B35:C::", "66566:576:57696869576969586969586:586969576969586857685868586766", "334155453546354635463547594658465846584658473546354634463546344635463446354634463547584657465746574657473546344634463446344755", "::456:466:466:466:466845:@46:@46:@46:@46:>4568466:4668466:4668466:4668466:4668466845:>46:>46:>46:>46:<45684668466846684667::", // bad "333531333434343132333434353531313335343434323232323334343435353231333133343556343434313233323335345935353532313331313132333233353535343557343133343556343434355934353531333459343434355935323335345935323335345935323335345935323335345935353455" "333531333434343132333434353531313335343434323232323334343435353231333133343556343434313233323335345935353532313331313132333233353535343557343133343556343434355934353535593432333234355935323335345935323335345935323335345935343459313334353455"}; BufferedImage img = new BufferedImage(1300, 1300, BufferedImage.TYPE_INT_RGB); g = img.createGraphics(); g.translate(500, 500); d(a[Integer.parseInt(args[0]) - 1]); String f = args[0] + ".png"; ImageIO.write(img, "png", new File(f)); } } 

Results (trimmed, negated, joined and scaled):

results

The shapes are quite unusual :) but correct as far as I can tell (let me know if you find any errors). They were generated (in a separate program) by constructing the face graph and cutting cycles in a DFS.

I'm sure this can be golfed quite a lot more using e.g. python and turtle.

Edit: oops, the last case was self-intersecting a bit. I fixed the code (by hand), here's the updated image:

13 corrected

\$\endgroup\$
5
  • \$\begingroup\$ Does the fix by hand mean the code still outputs a self intersection? Is that the only thing separating this from being a valid answer? \$\endgroup\$ Commented Apr 17, 2014 at 10:31
  • \$\begingroup\$ @githubphagocyte If it still outputted a self-intersection, it wouldn't be a fix. This is a valid answer. \$\endgroup\$ Commented Apr 18, 2014 at 2:56
  • \$\begingroup\$ This has been flagged because it violates one of the rules in our help center: All solutions to challenges should [...] be a serious contender for the winning criteria in use. For example, an entry to a code golf contest needs to be golfed. \$\endgroup\$ Commented Mar 11, 2016 at 16:48
  • \$\begingroup\$ @Dennis better now, mr. policeman? :p \$\endgroup\$ Commented Mar 11, 2016 at 17:24
  • 1
    \$\begingroup\$ Much better. \$\endgroup\$ Commented Mar 11, 2016 at 17:37
6
\$\begingroup\$

Mathematica

Out of competition, not a free language

f[n_] := PolyhedronData[Sort[PolyhedronData["Archimedean", {"FaceCount", "StandardName"}]][[n, 2]], "NetImage"] 

Usage:

f /@ Range@13 

Mathematica graphics

\$\endgroup\$
0
2
\$\begingroup\$

LOGO, 494 427 416 bytes

It's been over a decade but I thought I could beat Aditsu's long standing record of a little over 1500 bytes for a free language.

The latest golfed version contains shorter magic strings for polygon data (variable :p, 1 byte each saved for strings 5 and 6 for the rhombi- and truncated rhombi- solids) and consequently the numbers encoded by other magic strings are slightly different. The nets for the 4 affected polyhedra are still valid but less visually appealing than the ones shown below.

TO f :j make "k(:j-2)%6<5make "p item :j-6*(:j>7)[lHH JiIi J~I~ @m?h hGaFaEh |GnFnE| hJ`JaJhJaJbIh] for[a 0 3+6*(:j>7)][make "s -1^:a^:k pu setxy :a%2*(82-ascii item :j "DMBzK8RmzDhh-):a*(96-ascii item :j "HJ96=$APBHJ:K)seth :s*(36-ascii item :j "$~o~333ZT`BB7)pd for[b 2-or :k :a=1(count :p)-(:a>:k)][make "c ascii item :b :p make "e(21-int :c/4)*:s*.8^(:j<8)^((int :c/4)%5=1)repeat :c%4+abs :e[fd 16lt 360/:e]]]END 

A logo procedure expecting an integer 1-13 as described in the question. Online interpreter at https://www.calormen.com/jslogo/# . Paste in the procedure, paste the following test program below it and hit RUN.

cs ;clear screen f 3 ;draw shape (edit to desired number) ht ;hide turtle 

Output

The modified version of the code below is a full program that plots all 13 nets in non-overlapping areas of the screen. It has extra code to position each separate net, and the data for setxy and seth are not compressed into strings. The output is shown below. Nets are shown 1-13 from left to right (staggered to avoid overlap.) Unlike the procedure above, this code can be pasted into https://www.calormen.com/jslogo/# and run in a single step.

If you run this at the online intepreter and the plot area on your screen is too small, the image may wrap round. You may need to zoom out your browser to avoid this.

cs for [j 1 13] [make "k(:j-2)%6<5make "p item :j-6*(:j>7)[lHH JiIi J~I~ @m?h GaGhGaEh GnG|GnE| hJ`JaJhJaJbIh] for[a 0 3+6*(:j>7)][make "s -1^:a^:k pu setxy (:j-7)*120+:a%2*item :j[14 5 16 -40 16 44 0 -27 -40 14 -22 -22 37] -:j%2*250+:a*item :j [24 22 39 42 32 55 31 16 30 24 22 38 21] seth :s*item :j[0 -90 -75 -90 -30 -30 -15 -54 -48 -60 -30 -30 -19] pd for[b 2-or :k :a=1 (count :p)-(:a>:k)][make "c ascii item :b :p make "e(21-int :c/4)*:s*.8^(:j<8)^((int :c/4)%5=1) repeat :c%4+abs :e[fd 16lt 360/:e]]]] 

enter image description here

Explanation

Observations and definitions

There is one Archimedean solid based on the tetrahedron, 6 on the cube and 6 on the dodecahedron. These basic polyhedra have faces with different numbers of sides, but all have 3 faces meeting at each vertex.

In the drawing below we pick one pair of faces (top/bottom) of the cube and dodecahedron and call them polar (north/south). The other faces are equatorial. Both shapes have twice as many vertices and 3 times as many edges as they have equatorial faces.

The cube has 4 equatorial faces arranged inline around the equator. We can count all the edges & vertices of the cube by considering the edges to the north, west and south of each equatorial face, which form a C shape, meeting at the northwest and southwest vertices. Two such C shapes in green and blue are shown in the drawing.

The dodecahedron has 10 equatorial faces zigzagging around the equator, 5 to the north and 5 to the south. We can count all vertices and edges by forming a C shape in a similar way, from the northwest and southwest vertices and three adjacent edges of each equatorial face. Five such C shapes are shown in the drawing: green & blue to the north, and brown, red & purple to the south. We call the north vertices & edges of the north faces and the south vertices & edges of the south faces the 10 polar vertices/edges, as they border the polar faces in a similar way to the cube. We call the remaining 10 vertices & north/south edges equatorial vertices & edges as they form a ring at the equator.

Additionally the west edges can be referred to as "vertical" edges (though they are not strictly vertical for the dodecahedron.)

Fig: Edges and vertices forming C shapes around equatorial faces

Edges and vertices forming C shapes around equatorial faces

In the Archimedean solids we find: "main" faces corresponding to the faces of the cube or dodecahedron; triangular or hexagonal "vertex" faces corresponding to the vertices of the cube or dodecahedron, and (in some cases) "edge" faces corresponding to the edges of the cube or dodecahedron. The rhombicuboctahedron and truncated cuboctahedron have square "edge faces". The snub cube is derived from the rhombicuboctahedron by givng the main faces a slight twist, converting each of the square edge faces into a pair of triangles. The same applies for the analogous dodecahedron derivatives.

Repeating units

The nets are built up using repeating units corresponding to one equatorial face, the vertex faces (and if applicable, edge faces) from the C shape mentioned above, plus a polar face (only plotted twice per polyhedron.)

At the start of the code, one of several magic strings is assigned to :p corresponding to the required polyhedron. There are magic strings for the tetrahedron and all 6 polyhedra based on the dodecahedron, which encode the various polygons that need to be drawn to form 1/10th of the net.

There are no magic strings for polyhedra based on the cube. For these, the magic string for the analogous polyhedron with dodecahedral symmetry is used, and the pentagons & decagons are converted to squares & octagons by multiplying the number of sides by 0.8, giving a repeating unit corresponding to 1/4th of the net.

The repeating units are shown below, with the first polygon drawn shown in blue and the last polygon drawn (which is always the polar face) shown in yellow. For the snub polyhedra, the first polygon is also an alternate polar face and is shown in green. Note that the repeating units are identical for the 6 polyhedra based on the dodecahedron and the 6 analogous polyhedra based on the cube, except that the main faces are squares instead of pentagons.

Fig: Repeating units

enter image description here

The ascii code :c for each character encodes for one polygon. (21-int :c/4) recovers the number of sides, between -10 and 10. Positive numbers correspond to clockwise rotation, negative sides correspond to anticlockwise rotation. c%4 recovers a number between 0 and 3, which corresponds to a number of additional sides to be drawn to move the turtle. By alternating drawing clockwise and anticlockwise, chains of polygons can be drawn. Small side branches are also possible by drawing a polygon with :c%4 > 0, drawing a branch polygon with :c%4 = 0, then drawing the first polygon with :c%4 > 0 to move the turtle to a different side of the polygon. The code fd 16 lt 360/:e is what actually draws one side of an e sided polygon (with a sidelength of 16, chosen because cos 30 is almost exactly 7/8.)

Rotation, reflection and translation of repeating units

The repeating units are drawn by looping the variable :a from 0 to 3 or 0 to 9. :s is +1 for even iterations and -1 for odd iterations and is used to reverse the direction of the turns during drawing so that a reflected version is produced. This is essential for the polyhedra based on the dodecahedron due to its zigzag of equatorial vertices. It is not essential for all the polyhedra based on the cube, but is done anyway as it helps place the polar faces correctly. It is very helpful in correctly orientating the units the cuboctahedron and truncated octahedron.

The builtin seth is used to set the heading of the turtle before plotting each repeating unit. the argument for seth is stored in a magic string (one character per polyhedron) and is multiplied by :s to get the correct angle after reflection

Reflection is not applied for the snub polyhedra, which have no reflectional symmetry. The variable :k is 0 for a snub polyhedron and 1 otherwise. The expression used to calculate :s is -1^:a^:k (stacked powers are evaluated left to right in LOGO so this is effectively multiply :a by :k and raise -1 to that power.)

The repeating units are positioned by translation by setxy. The correct amount of vertical translation is applied to the y value using a magic string with one character per polyhedron. Vertical translation is used due to the fact that seth considers angle zero to be upward. Zigzagging is applied by extracting an x offset from another magic string (one character per polyhedron) and multiplying by :a%2. Hence the centreline of the net is the average of zero and the number in the magic string. Some degree of zigzag is required for 12 out of 13 polyhedra (even those based on the cube - only the snub cube is excepted.) Although some of the cube nets are quite symmetrical, the start point of the repeating units is not generally on the centreline.

Observation: The repeating units for the dodecahedron derivatives with edge faces (rhombicosidodecahedron, truncated rhombicosidodecahedron and snub dodecahedron) are aligned equatorial edge face to vertex face on a hexagonal grid (with slight rotation for the snub.) For the analogous polyhedra based on the cube, the alignment is main face to vertical edge face. This follows the observation above that the faces of the cube sit at the equator (separated by vertical edges) while on the dodecahedron it is the equatorial vertices that sit at the equator (joined by the equatorial edges.) The icosidodecahedron is linked via its equatorial main faces and equatorial vertex faces. The cuboctahedron is linked through its main faces and some of its vertex faces (alternating north/south.) The truncated icosahedron and octahedron are similar but only link through the vertex faces. The truncated dodecahedron and cube follow a similar pattern to typical nets for the regular dodecahedron and cube: equatorial edges for the dodecahedron, vertical edges for the cube.

Suppression of unwanted polar faces

In general we only want to plot the last face from the magic string (the polar face) twice. We do this on the first 2 iterations of the :a loop. For the snub polyhedra we only want to do it once. This is achieved using the final condition in loop for[b 2-or :k :a=1 (count :p)-(:a>:k)] where count :p is the total number of polygons encoded in :p, and :k is 0 for a snub polyhedron or 1 for any other. Also, for snub polyhedra an alternate polar face is encoded at the beginning of :p and we only want to plot this on iteration 1. This is achieved by the initial condition 2-(or :k :a=1) which is 1 for non-snub polyhedra (because :k=1) and 2 for snub polyhedra (except when a=1)

The truncated tetrahedron is plotted in the exact same way as the cube derivatives, with 4 iterations fof the :a loop, except that we do not want to plot any polar faces. The magic string for the truncated tetrahedron therefore contains two copies of the character used to plot the triangle, so that the triangle is drawn twice on the first two iterations of the a loop instead of drawing an additional polar face.

Commented code This is a commented version of the code used to generate the above combined output image (which differs slightly from the golfed code as explained in the text.)

cs for [j 1 13][ ;loop through 13 polyhedra j=1 to j=13 make "k(:j-2)%6<5 ;k=0 for snub polyhedra, 1 otherwise make "p item :j-6*(:j>7)[lHH JiIi J~I~ @m?h GaGhGaEh GnG|GnE| hJ`JaJhJaJbIh] ;Store magic string for selected polygon in p. Same string used for 8-13 as for 2-7 for[a 0 3+6*(:j>7)][ ;Loop a. 4 times for cube/tetrahedron based polyhedra, 10 times for dodecahedron based polyhedra make "s -1^:a^:k ;s=-1^a (alternate sign for even/odd iterations of a.) Do not alternate for snub polyhedra k=0 pu ;Pen up prior to moving (polyhedron net will be drawn in 4 or 10 equal parts) setxy (:j-7)*120+ :a%2*item :j[14 5 16 -40 16 44 0 -27 -40 14 -22 -22 37] ;Move based on coordinates x=a%2*value and y=a*value (values from arrays selected by j for each polyhedron.) -:j%2*250+ :a*item :j [24 22 39 42 32 55 31 16 30 24 22 38 21] ;Initial code (:j-7)*120 and -:j%2*250 is used to position the 13 nets in this version (not used in golfed version) seth :s*item :j[0 -90 -75 -90 -30 -30 -15 -54 -48 -60 -30 -30 -19] ;Set heading based on value selected by j. Positive or negative depending on value of s pd ;Pen down for[b 2-or :k :a=1 ;Loop b through polygons encoded by magic string. For snub polyhedra skip the 1st unless a=1. For others start at 1st k=1 (count :p)-(:a>:k)][ ;End at last polygon (count :p) for 1st iteration of loop a (snub polyhedra) or 1st two (others) otherwise skip last make "c ascii item :b :p ;Extract character c from magic string p. Find number of edges (positive or negative) encoded by 21-int c/4 make "e(21-int :c/4)*:s*.8^(:j<8)^((int :c/4)%5=1) ;Multply by s to invert if necessary. If the number of edges is divisible by 5 and j<8, multiply by 4/5=0.8 repeat :c%4+abs :e[fd 16lt 360/:e] ;Draw a polygon with e edges, repeating c%4 additional edges to move the turtle as necessary. ]]] 
\$\endgroup\$