Drawing 3d nets - Platonic solids

14

2

This is a basic version of the rather more difficult Drawing 3d nets - Archimedean solids .

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, write the shortest program you can that draws nets for the 5 Platonic solids. The output should be an image file in any sensible format of your choosing (png, jpg, etc.).

All five shapes are described at http://en.wikipedia.org/wiki/Platonic_solid . Their nets looks like this (taken from http://www.newscientist.com/gallery/unfolding-the-earth/2 ).

enter image description here

Input: An integer from 1 to 5. Assume the shapes are numbered in order of the number of sides they have. So, 1 would be a tetrahedron and 5 the icosahedron.

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.

Winner. Only one entrant but it was wonderful. The winner is ... Raufio for what is my favourite piece of code golf ever.

felipa

Posted 2013-02-10T19:34:10.100

Reputation: 895

Answers

8

Python, 456 429 381

import turtle as t
L="fl"
R="fr"
d=L*3+R*3
b=(d+R)*3
a=[b,120,L*3+"fflflffflflfrflflfffl"+R*4+"flf",90,b+"ffrfrflffrffrfrfrflflf",120,(R*5+L*5+R+L)*5+"rrfr"+L*5+R*2+L*2+R*4+"f",72,(d+"f")*5+"rfl"+((d+"b")*5)[:-1],120]
l=t.lt
f=t.fd
b=t.bk
r=t.rt
p=input()*2-2 
t.setup(.9,.9)
t.goto(-200,150)
t.clear()
for c in a[p]:exec c+"(a[p+1])"
t.getscreen().getcanvas().postscript(file="o")

I implemented a primitive interpreter with l r f b as operators that move the turtle cursor around at the angle of the shapes. At one time, it turns only one angle. I compressed the strings by reusing strings (kind of like psuedo-subroutines), other than that, I didn't check to see if I was using the best path. It outputs to a postscript file.

A little explanation of un-golfed code:

import turtle as t
Left="fl"
Right="fr"
diamond= Left*3 + Right*3
tetrahedron=(d+R)*3 #used to be b

Imports the built-in turtle module and defines the macros that shorten the strings. The turtle module uses commands to move a 'turtle' around the screen (ie forward(100), left(90))

netList=[
   #tetrahedron
   tetrahedron,120,
   #cube
   Left*3+"fflflffflflfrflflfffl"+Right*4+"flf",90,
   #octohedron, builds off the tetrahedron
   tetrahedron+"ffrfrflffrffrfrfrflflf",120,
   #dodecahedron
   (Right*5 + Left*5 + Right + Left)*5
    +"rrfr"+
    Left*5 + Right*2 + Left*2 + Right*4 + "f",72,
   #icosahedron
   (diamond+"f")*5 +"rfl"+((diamond+"b")*5)[:-1],120
]

This list holds the angles and movement sequences. The tetrahedron was saved to reuse with the octohedren.

l=t.left
f=t.forward
b=t.back
r=t.right

This is the part that i like, it makes single character local functions so the calls can be shortened and automated through pre-defined strings.

input=int(raw_input())*2-2 
t.setup(.9,.9)
t.goto(-200,150)
t.clear()

This starts by taking the input (between 1 and 5), and converting that to an index that points to the shape string in the netList. These setup turtle to show the whole net. These could be left out if the task was just to draw them, but since we need a picture output they are needed.

for command in netList[input]:
    exec command+"(netList[input+1])"
t.getscreen().getcanvas().postscript(file="o")

The for loop takes the commands in the command sequence string and executes them, so for a string like "fl", this executes "forward(angle);left(angle);" by calling the newly created local functions. the last line outputs a file called 'o' that is in postscript format format using turtle function.

To run:

Copy it into a file and run it from there. When you run it, it will wait for a number input between 1 and 5 (i just changed it so that it asks before setting up turtle). When you input a number, a window pops up and draws the net. if you want it to go faster you can add t.speed(200) before setup.

You can copy-paste it into the interpreter, but when raw_input() is called it consumes the next string you input "t.setup(.9,.9)" instead of a number. So if you do this, copy up until raw_input(), input a number, than copy paste the rest. It is intended to be run as a whole. Or you could copy it into a function and call it.

Here are it's outputs (converted from postscript):

Note: the position of these in the window has changed, but their overall shape is the same.

tetrahedron cube octahedron dodecahedron icosahedron

It's a little brute force for code golf, but I got tired of trying to find a consistent pattern between the shapes.

Raufio

Posted 2013-02-10T19:34:10.100

Reputation: 216

Very close. The dodecahedron is definitely more tricky. – felipa – 2013-02-12T07:54:36.283

@Raufio It's very nice. Is it not possible to define a triangle (or square or pentagon) and then just rotate/move it about? Or is that effectively what you have done? – felipa – 2013-02-12T21:52:12.370

Effectively, yes that is what I did, but with larger shapes. For instance, the icosahedron is drawn by drawing two triangles, one on top of the other, and moving forward 5 times, then resetting at a new location, drawing the diamond again moving back then repeating 5 times. d is the string that does the two triangles, so it is (d+'f')*5+setupPosition+(d+'b')*5 – Raufio – 2013-02-12T22:44:14.737

@Raufio The golfed code doesn't work for me. It opens a window that is mostly blank. If I then press return I get p=(ord(raw_input())-49)*2
TypeError: ord() expected a character, but string of length 0 found
– felipa – 2013-02-13T10:43:12.017

@Raufio I tried it line by line in ipython and I don't really get it. I mean what is t.setup(.9,.9) t.goto(-200,150) t.clear() for? And then what is p=(ord(raw_input())-49)*2 meant to do? – felipa – 2013-02-13T10:46:49.187

1@felipa setup makes the turtle window to be big enough to hold the net. Same thing with goto, it moves the 'turtle' to -200, 150. clear clears the line made by goto. Their just commands for setting up drawing. p=(ord(raw_input())-49)*2 takes a number, 1 through 5, corresponding to what shape you want. – Raufio – 2013-02-13T15:53:43.240

@Raufio Oh I take it back. It's beautiful :) – felipa – 2013-02-13T16:11:20.857

6

Mathematica

Out of competition, not a free language (unless a free trial counts as free)

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

Usage:

f /@ Range@5

Mathematica graphics

Dr. belisarius

Posted 2013-02-10T19:34:10.100

Reputation: 5 345

@felipa it's free as in beer on the Raspberry Pi. – shrx – 2015-12-10T14:34:10.430

you know, on that free computer, the raspberry pi – undergroundmonorail – 2015-12-10T14:43:50.187

1Mathematica is definitely not free in either sense. Very nice answer however. – felipa – 2013-02-10T22:27:24.710

6

Python 2 (with cairo) - 239

from cairo import*
s=PSSurface(None,99,99)
g=Context(s)
g.move_to(30,20)
a=str([34,456,3455,568788,3454445555][input()-1])
f=6.28
for c in a+a[::-1]:exec'g.rel_line_to(8,0);g.rotate(f/int(a[0]));'*int(c);f=-f
g.stroke()
s.write_to_png('o')

Results:

results

aditsu quit because SE is EVIL

Posted 2013-02-10T19:34:10.100

Reputation: 22 326

3

Logo, 199 bytes

TO p:d:n:s
rt :n*45 for[i 1 :n/8][pu setxy :d*:i 0 pd repeat 2[for[k 1 :s*2+2][fd 40 rt (360-720*(:k>:s))/:s] rt 720/:s]]END
TO q:j
apply "p item :j [[70 9 3][56 23 4][70 16 3][105 26 5][40 42 3]]END

Reading this back I see my original version did not comply with the spec as written (take a numerical argument and draw one shape) but rather as interpreted by some of the other answers (draw all shapes.) The new version fixes this. It expects to be called as for example q 5. cs should be done before to clear the screen and point the turtle north.

q calls the main function p with 3 arguments. The syntax for this is pretty bloated, so to beat my previous score I had to shave off bytes elsewhere.

the new version of p takes 3 arguments. There is no need for x and y because we only plot one net, but d the pitch between subunits remains. s is still the number of sides per polygon, and n now encodes for two different things> n/8 is the number of subunits to be plotted, and n*45 is an angle through which the turtle must be turned before starting (taking advantage of the natural mod 360 for rotations.)

Improved looping accomplishes drawing s lines with righthand rotation and s+2 lines with lefthand rotation in a single loop.

the calormen interpreter seems to be less tolerant of missing whitespace now than at the time of my first post, but the code runs fine on http://turtleacademy.com/playground/en

Logo, 200 bytes

TO p:x:y:d:n:s
for[i 1:n][pu setxy:x:y-:d*:i if:i<>6[pd]repeat 2[repeat:s[fd 40 rt 360/:s]repeat:s+2[fd 40 lt 360/:s]rt 720/:s]]END
p 0 200 40 7 3
p 70 0 80 2 3
p -200 200 105 3 5
rt 45
p 90 90 56 2 4

Interpreter at http://www.calormen.com/jslogo/# It is assumed the turtle is pointing North before the program is run. Use the cs command to clear the screen, point the turtle north, and place it at the origin in the centre of the screen.

enter image description here

The basic unit of all the above nets is a pair of back to back polygons. These are arranged in 2 staggered rows, making a subunit of 4 polygons which can be translated vertically to make all the nets (except the octahedron, which hitches a ride on the drawing of the icosahedron and tetrahedron). The subunit forms 1 tetrahedron net, 1/5 of the icosahedron net, 1/3 of the dodecahedron net and 2/3 of the cube net (two subunits are drawn, with the middle two squares overlapping.)

Ungolfed code

TO p :x :y :d :n :s                 ;x,y=starting point d=negative vertical offset for each iteration n=#of iterations s=# of sides on polygon
  for[i 1 :n][                      ;iterate n times 
    pu                              ;pen up
    setxy :x :y- :d* :i             ;move pen to start of iteration
    if :i<>6[pd]                    ;pen down (supressed for i=6 to enable part of octahedron to be drawn with icosahedron)
    repeat 2[                       ;draw lower row of 2 polygons, then upper row of 2 polygons
      repeat :s[fd 40 rt 360/ :s]   ;starting at lower left of polygon facing up, draw righthand polygon
      repeat :s+2[fd 40 lt 360/ :s] ;starting at lower right of polygon facing up, draw lefthand polygon, duplicating last two sides
      rt 720/ :s                    ;return turtle to upwards facing in order to draw second row
    ]
  ]
END
cs
p 0 200 40 7 3                      ;draw icosahedron and left side of octahedron (6th iteration is suppressed)
p 70 0 80 2 3                       ;draw right side of octahedron, and tetrahedron
p -200 200 105 3 5                  ;draw dodecahedron
rt 45                               ;turn turtle in preparation for drawing cube
p 90 90 56 2 4                      ;draw cube

Level River St

Posted 2013-02-10T19:34:10.100

Reputation: 22 049

@phase haha, thanks, I actually considered doing a ht to hide it for the image. I'm glad I didn't! – Level River St – 2015-12-28T04:49:14.317