Draw Reutersvärd's Triangle

33

5

This impossible object is Reutersvärd's triangle:

enter image description here

Draw your own version according to these rules:

  • Exactly 9 cubes total
  • Each side is made up of exactly 4 cubes
  • The cubes appear to overlap such that the rendered object is in fact an impossible object
  • 4 distinct colours are used - one for the background and 3 for each of the faces of the cubes
  • In bitmap output, the full triangle should be at least 100 pixels tall and at least 100 pixels wide
  • Aspect ratio: the width and height of the full triangle should not be off by more than a factor of 2
  • The triangle may be rotated by any amount relative to the above image
  • The triangle may or may not be reflected relative to the above image

Digital Trauma

Posted 2017-01-14T01:13:00.330

Reputation: 64 644

Answers

14

Brain-Flak, 487810 327722 75564 + 1 = 75565 bytes

Unfortunately this is a tad big to fit in an answer.

PasteBin

Try it Online

With the -A flag this outputs an ASCII ppm file that looks as follows:

New output

Explanation

You may have already guessed I did not write this by hand. So here's how I did it:

I first made the image you see above from the image provided by the challenge. It has the distinction of having no color channel that is at any value other than 255 or 0 this way we can wrap it up into a smaller file with the max color channel set to 1. I then wrote a python script to golf a Brain-Flak program that solves this using a module I wrote myself that can be found here. Its not very polished its just a hack I threw together for things like this. push is a function that returns efficient Brain-Flak code to push a number to the stack and kolmo is a very simple Kolmogorov complexity solving program that attempts to find an efficient way to push a particular string to the stack.

from value import push,kolmo

def group(a, n):
    return zip(*[a[i::n]for i in range(n)]) 

f=open("R.ppm")
a=["".join(x)for x in group(f.read().split()[3:][::-1],3)]
f.close()

def hardcode(string):
    result = push(ord("\n")).join("(<>({})<>"+{"0":"","1":"()"}[x]+")"for x in string)
    return result

last = ""
acc = 0
result = push(ord("0"))+"<>"
for x in a+[""]:
    if x != last:
        string = ("" if not last else kolmo("\n")+hardcode(last))
        result += min([push(acc)+"{({}[()]<%s>)}{}"%string,acc*string],key=len)
        acc=1
    else:
        acc += 1
    last = x
print result+kolmo("P3 100 100 ")

This was quite fun and I hope to improve my answer

Post Rock Garf Hunter

Posted 2017-01-14T01:13:00.330

Reputation: 55 382

14You legitimately golfed away 160088 bytes? Is that a record? – Neil – 2017-01-14T10:49:08.800

Maybe some unary answers can beat that – Roman Gräf – 2017-01-14T14:34:56.083

7

@Neil Not even a personal one

– Post Rock Garf Hunter – 2017-01-14T15:04:37.117

Your Python code intrigues me. What's value? (Not this module on PyPI, I'm guessing?) What's kolmo?

– Tim Pederick – 2017-01-14T17:46:45.907

@TimPederick Sorry about that. Thats a module a wrote myself for golfing Brain-Flak. I will include a link in the body. – Post Rock Garf Hunter – 2017-01-14T17:49:49.097

13

Mathematica, 237 bytes

n={-1,1}#&;c_~g~s_:=Polygon[c+s#&/@{k={12,9},m=n@k,t={0,-12}}];p={#,#2~g~1,#3~g~-1}&;a=p[Cyan,#-k,#+m]&;b=p[Blue,#-t,#+k]&;c=p[Red,#-m,#+t]&;Graphics@{{a@#,b@#,c@#}&/@{j=4k,s=4{4,9},n@s,4m,r={-32,8},q=-4{4,5},4t,n@q,n@r},a@j,b@s,c@j,c@s}

Easier-to-read version:

1  n = {-1, 1} # &;
2  c_~g~s_ := Polygon[c + s # & /@ {k = {12, 9}, m = n@k, t = {0, -12}}];
3  p = {#, #2~g~1, #3~g~-1} &;
4  a = p[Cyan, # - k, # + m] &;
5  b = p[Blue, # - t, # + k] &;
6  c = p[Red, # - m, # + t] &;
7  Graphics@{
8    {a@#, b@#, c@#} & /@
9      {j = 4 k, s = 4{4, 9}, n@s, 4 m, r = {-32, 8},
10       q = -4{4, 5}, 4 t, n@q, n@r},
11   a@j, b@s, c@j, c@s}

Line 1 defines a function n that negates the first coordinate of an ordered pair. Line 2 defines a function g that produces a (roughly) equilateral triangle centered at the point c, and pointing down or up depending on whether s is 1 or -1. Line 3 defines p to be a parallelogram template consisting of a color and two triangles, and lines 4–6 define a, b, and c to be the three different specific types of parallelograms that appear in the cubes.

Line 8 defines a function {a@#, b@#, c@#}& that draws an entire cube centered at the point #; lines 9 and 10 apply that to the nine points needed to make the larger triangle. This produces nine cubes, starting at the upper right and going counterclockwise, where the later ones cover up parts of the earlier ones. Finally, line 11 redraws four parallelograms (in the upper right of the picture) so that they end up covering the later cubes as they're supposed to. The output is below:

enter image description here

Greg Martin

Posted 2017-01-14T01:13:00.330

Reputation: 13 940

6Wait what Mathematica doesn't have a built-in for this? – Digital Trauma – 2017-01-15T03:09:57.353

10

HTML + CSS 3D (855 866 bytes)

HTML 117 bytes + CSS 738 bytes

To keep the z-indexes in order was a bit tricky. ;)

/* CSS */
p{position:absolute;left:110px;top:0;width:50px;height:50px;transform-style:preserve-3d;transform:rotateX(-45deg)rotateY(21deg)rotateZ(20deg)}
p+p{left:140px;top:50px}
p+p+p{left:170px;top:100px}
p+p+p+p{left:200px;top:150px}
p+p+p+p+p{left:140px;top:150px}
p+p+p+p+p+p{left:80px;top:150px}
p+p+p+p+p+p+p{left:20px;top:150px}
p:nth-child(8){z-index:1;left:50px;top:100px}
p:nth-child(9){z-index:-1;left:80px;top:50px}
p:nth-child(10){z-index:1;left:67px;top:59px;transform:rotateX(-45deg)rotateY(21deg)rotateZ(20deg)scale(0.6)}
a{position:absolute;width:50px;height:50px;background:red;transform:rotateY(0deg)translateZ(25px)}
a+a{background:tan;transform:rotateY(-90deg)translateZ(25px)}
a+a+a{background:navy;transform:rotateX(90deg)translateZ(25px
<!-- HTML -->
<p><a><a><a><p><a><a><a><p><a><a><a><p><a><a><a><p><a><a><a><p><a><a><a><p><a><a><a><p><a><a><a><p><a><a><a><p><a><a>

I've kept the new lines for better readability. Maybe somebody spots potential for more golfing. However, they are not included in the byte count.

Result

enter image description here

jsFiddle Demo

Try it yourself

Use Goole Chrome. Other browsers may have problems with the z-indexes.

Edit

  • Saved 2 bytes by removing the duplicate a-selector, thanks to ETHproductions.
  • Saved 9 bytes by removing an unnecessary margin:0 on the a-element.

insertusernamehere

Posted 2017-01-14T01:13:00.330

Reputation: 4 551

Is it still valid HTML without HEAD/BODY and closing tags? I know browsers tend to ignore syntax errors and try to display whatever you throw at them, but I don't think this code follows the specs. (That said, great solution!) – Federico Poloni – 2017-01-15T08:59:09.107

2

@FedericoPoloni Thank you. Regarding the html|head|body-elements: They can be omitted. Take a look at "Optional Tags", you'll be surprised how many elements and closing tags can be omitted as well. What is not in the specs but works too is to omit the closing tags of the a-elements. They are however closed correctly by the browser, because you can't nest them. Also from the Code Golf point of view: Everything that "compiles" and has the correct output is valid. ;)

– insertusernamehere – 2017-01-15T15:03:01.063

9

BBC BASIC, 147 bytes

tokenised filesize 129 bytes

t=PI/1.5x=500y=x:FORi=0TO28b=i MOD3GCOL0,b:b*=t:a=i DIV9*t:IFb=0x-=99*COSa:y-=99*SINa
MOVEx,y:VDU25;66*COSb;66*SINb;28953;66*COS(b-t);66*SIN(b-t);:NEXT

2 bytes saved by using an absolute coordinate specification (MOVE) and two relative specifications per parallelogram, instead of changing the origin in order to be able to use all absolute specifications. 1 byte of unnecessary whitespace eliminated.

BBC BASIC, 150 bytes

tokenised filesize 127 bytes

Download interpreter at http://www.bbcbasic.co.uk/bbcwin/download.html

t=PI/1.5x=500y=x:F.i=0TO28b=i MOD3GCOL0,b:b*=t:a=i DIV9*t:IFb=0 x-=99*COSa:y-=99*SINa:ORIGINx,y
L.66*COSb,66*SINb,0,0PLOT117,66*COS(b-t),66*SIN(b-t)N.

Explanation

We start with the coordinates at top right and plot rhombuses in groups of 3. Before each group of 3 we move the origin (West, West, West, SE, SE SE, NE, NE NE.) That means that the group of 3 at top right is the last complete group to be plotted, bringing the origin back to its original location. We then continue and plot the black and red (but not the green) of the first group again, a total of 29 rhombuses.

Ungolfed

  t=PI/1.5                                 :REM 120 deg
  x=500                                    :REM coordinates of top right corner
  y=x
  FORi=0TO28
    b=i MOD3:GCOL0,b                       :REM set colour 0=black,1=red,2=green
    b*=t                                   :REM convert b to a multiple of 120deg
    a=i DIV9*t
    IFb=0 x-=99*COSa:y-=99*SINa:ORIGINx,y  :REM before each group of 3 rhombs move the graphics origin
    LINE66*COSb,66*SINb,0,0                :REM define one side of a rhombus
    PLOT117,66*COS(b-t),66*SIN(b-t)        :REM define one further corner and plot the rhombus
  NEXT

Output

enter image description here

Level River St

Posted 2017-01-14T01:13:00.330

Reputation: 22 049

8

HTML + JavaScript (ES6), 351 374 384

<canvas id=C></canvas><script>c=C.getContext("2d");`133124222162184253104213162164244191224182133191064104222093164253122224284151284`.match(/.../g).map((v,i)=>(c.fillStyle=['#fc0','#f04','#08a'][a=i%3],c.beginPath(),c[l='lineTo'](x=5*~~v/10,y=v%10*25),c[l](x-10,y+(--a+!a)*17),a&&c[l](x-30,y+a*17),c[l](x-20,y),!a&&c[l](x-10,y-17),c.fill()))</script>

Less golfed

<canvas id=C></canvas>
<script>
  c=C.getContext("2d");
  [133,124,222,162,184,253,104,213,162,164,244,191,224,182,133,191,64,104,222,93,164,253,122,224,284,151,284]
  .map((v,i)=>(
    a = i % 3,
    x = 5 * ~~ v / 10,
    y = v % 10 * 25,
    c.fillStyle = ['#fc0','#f04','#0a8'][a],
    c.beginPath(),
    --a,
    c[l='lineTo'](x, y),
    c[l]( x -10, y + (a+!a) * 17),
    a&&c[l](x - 30, y + a * 17),
    c[l](x - 20, y),
    !a&&c[l](x - 10, y - 17),
    c.fill()
  ))
</script>

Test

<canvas id=C></canvas><script>c=C.getContext("2d");`133124222162184253104213162164244191224182133191064104222093164253122224284151284`.match(/.../g).map((v,i)=>(c.fillStyle=['#fc0','#f04','#08a'][a=i%3],c.beginPath(),c[l='lineTo'](x=5*~~v/10,y=v%10*25),c[l](x-10,y+(--a+!a)*17),a&&c[l](x-30,y+a*17),c[l](x-20,y),!a&&c[l](x-10,y-17),c.fill()))</script>

edc65

Posted 2017-01-14T01:13:00.330

Reputation: 31 086

5

JavaScript(ES6)/SVG(HTML5), 350 312 bytes

document.write(`<svg width=390 height=338>`)
a=`195,52;240,130;285,208;330,286;240,286;150,286;60,286;105,208;150,130;`
a=(a+a).split`;`
for(i=9;i--;)document.write(`<path fill=#FD0 d=M${a[i]}h60l-30,-52h-60z /><path fill=#088 d=M${a[i+3]}h60l-30,52h-60z /><path fill=#F64 d=M${a[i+6]}l-30,-52l-30,52l30,52z />`)

Neil

Posted 2017-01-14T01:13:00.330

Reputation: 95 035

3

SVG, 562 540 520 504 487 473 bytes

This is my first time golfing SVG (or any markup, in fact); be gentle!

The assumed viewing environment is an SVG-capable web browser with anything like a typical window size. I tested it in Firefox 50 and in Chrome 55.

The viewBox is necessary to meet the 100-pixel requirement; blowing up all measurements by a suitable factor would also work but would take more bytes. Incidentally, it is possible to save another byte by removing the space in 0 -5 in the viewBox value, but Firefox won't accept this as valid (whereas Chrome will).

The aspect ratio is 1:1 instead of the true 0.866:1. I'm not sure exactly how the "factor of 2" rule is meant to be interpreted (I think it means that exaggeration as extreme as 0.433:1 or 1.732:1 is acceptable), but I'm pretty sure this meets the requirement anyway.

SVG

<svg xmlns="http://www.w3.org/2000/svg"
xmlns:l="http://www.w3.org/1999/xlink"
viewBox="0 -5 26 26"><g
id="a"><path d="m7,9H3V5h6z"/><g
id="f"><path fill="red" d="m9,5H3V1h4z"/><path
fill="blue" d="m3,1l2,4L3,9l-2-4z"/></g></g><use
l:href="#a" x="3" y="6"/><use
l:href="#e" x="12"/><g
id="e"><use l:href="#a" x="-6" y="12"/><use l:href="#a" x="-12" y="12"/></g><use
l:href="#a" x="-9" y="6"/><use
l:href="#a" x="-6"/><use
l:href="#a" x="-3" y="-6"/><use
l:href="#f"/></svg>

Result

A PNG rendering of the above SVG code for Reutersvärd's Triangle

Tim Pederick

Posted 2017-01-14T01:13:00.330

Reputation: 1 411

I think you could probably delete the newlines here, couldn't you? IIRC, XML disregards whitespace in most contexts. – None – 2017-01-14T15:49:38.653

@ais523: Yeah, I forgot to do that before posting it. facepalm It's done now, though. There's still newlines, keeping it vaguely readable, but only in places (namely between tag names and attributes) where a space of some sort is needed anyway. – Tim Pederick – 2017-01-14T15:52:24.377

Your interpretation of the aspect ratio rule is correct – Digital Trauma – 2017-01-15T03:12:15.947