Mondrian painting description language

16

4

This challenge consists in coding an interpreter for a Mondrian painting description language (MPDL).

Language definition

The language operates on a stack of rectangles. A rectangle is defined by its upper left coordinate and lower right coordinate. Coordinates must be integers. The stack is initialized with a single rectangle with attributes (1,1,254,254)

Each command has the following format: <character><integer>

There are three commands:

v<integer> : perform a vertical split on the latest rectangle in the stack, at the position indicated by the parameter (as percentage). The source rectangle is removed from the stack and replaced with the two new rectangles that result of the split. The left rectangle is pushed on the stack, then the right rectangle. As rectangle coordinates are integers, fractions should be rounded to biggest smaller integer.

h<integer> : horizontal split. The top rectangle is pushed on the stack, then the bottom rectangle.

c<integer> : removes the latest rectangle from the stack and paints it to the color given as parameter. 1 = white, 2 = red, 3 = blue, 4 = yellow

Challenge

Write a program that takes as parameter a painting description and creates a 256x256 bitmap representation of the painted rectangles. The rectangles must be separated with a 3 pixel black line. A one or two pixel rectangle should have his non-black pixels hidden by the border black pixels.

The input can be read as a parameter or as a file, up to you. The commands should be separated by a space. You can assume that the input file has correct syntax and does not have trailing or leading spaces, tabs, etc. The output can be directly displayed on the screen, or saved to a file, up to you.

The shortest code wins.

Test

The following source:

v25 h71 v93 h50 c4 c1 c1 c2 h71 c3 h44 c1 c1

Should produce the Composition II in Red, Blue and Yellow:

enter image description here

Arnaud

Posted 2014-10-31T04:50:56.387

Reputation: 8 231

3

Really hoping someone writes a solution in Piet!

– Skyler – 2015-10-19T14:46:55.353

1The language isn't great. v and h arguments should be in pixels – John Dvorak – 2014-10-31T04:58:15.097

Also, I'm not sure what's the point of rotating the stack instead of popping. – John Dvorak – 2014-10-31T04:59:58.227

Using percentages allows you to choose whatever size for the output bitmap - the result will be same (only it will be scaled) – Arnaud – 2014-10-31T05:00:22.617

But... why would you modify them later rather than immediately? – John Dvorak – 2014-10-31T05:01:44.377

What are the allowed output formats? Any image format or displaying on screen are all OK? – John Dvorak – 2014-10-31T05:17:40.470

What are the allowed input formats? Are we required to be able to handle newlines, or we may choose? – John Dvorak – 2014-10-31T05:37:08.940

@Jan I update the question to add precisions on output/input formats. Basically : they are free. – Arnaud – 2014-10-31T06:53:01.917

I think a language definition using [hv]<n> followed by description of the first rectangle then the second and explicit end of particular branch (either though [c] or a new directive) would make the challenge more interesting allowing for more diverse implementation. This version basically mandates implementing the stack as in the problem definition. – nutki – 2014-10-31T07:46:49.683

@nutki You are right. We could have a functional notation as v30(h50(c1,c5),h70(v50(c1,c3),c2)). I choose the language above because I though parsing would be simpler. – Arnaud – 2014-10-31T07:50:28.713

1Yeah something like that, but note you can still do without extra syntax elements as all operators have constant number of parameters. So the above can be still parsed when represented as v30 v50 c1 c5 h70 v50 c1 c3 c2. – nutki – 2014-10-31T08:12:29.187

@nutki Agree with you. I hesitate modifying the question, as it has already go through sandbox validation and some may have started coding it? – Arnaud – 2014-10-31T08:19:40.760

The example would be v25 h71 v44 c1 c1 c3 h71 c2 v93 h50 c1 c4 – nutki – 2014-10-31T08:23:51.060

@SuperChafouin I know, it's up to you. You could always allow both formats of the input. – nutki – 2014-10-31T08:26:02.810

@SuperChafouin Also adopting between solutions is not that hard as the only difference to the description is that c now pops the stack and there is no r operation. But the stack operation of h and v would stay as in the original. – nutki – 2014-10-31T08:28:57.407

@SuperChafouin "Sandbox validation" isn't anything sacred :P It's your challenge and it's brand new with no answers. Its hardly a risk to add in good ideas. – Calvin's Hobbies – 2014-10-31T08:49:24.827

Why 'to be painted' flag in the new version? Am I missing something why you wouldn't be able to paint it straight away like it the original description? – nutki – 2014-10-31T09:04:48.543

@Martin I prefer using percentages as they also carry semantics about the painting : e.g. split the rectangle at two thirds and paint it yellow. Don't think Mondrian was thinking in pixels :-) Also, no antialiasing because numbers are always rounded. – Arnaud – 2014-10-31T11:46:41.067

Last point, I'd like the description language to be universal and work for any picture size, even if in this specific golf, a fixed bitmap size is given. – Arnaud – 2014-10-31T11:53:42.203

Answers

6

Perl 5 + ImageMagick - 297

Something to start with:

sub a{my($x,$y,$X,$Y,$d)=@_;$_=shift@ARGV;
/v/?a($d=$x+($X-$x)*$'/100,$y,$X,$Y).a($x,$y,$d,$Y):
/h/?a($x,$d=$y+($Y-$y)*$'/100,$X,$Y).a($x,$y,$X,$d):
/c/&&"-fill ".qw/white red blue yellow/[$'-1]." -draw 'rectangle $x,$y $X,$Y' "}
system"convert -size 256x256 -stroke black xc: ".a(0,0,255,255)."a.gif"

Takes input on command line and generates a.gif.

nutki

Posted 2014-10-31T04:50:56.387

Reputation: 3 634

2

Haskell - 335

import Diagrams.Prelude
import Diagrams.Backend.SVG
c=centerXY
d((x:n):i)|x=='v'=(b#scaleX s#c|||a#scaleX(1-s)#c,k)|x=='h'=(b#scaleY s#c===a#scaleY(1-s)#c,k)|x=='c'=(square 1#fc([white,red,blue,yellow]!!(read n-1)),i)where{s=(read n)/100;(a,j)=d i;(b,k)=d j}
main=getLine>>=renderSVG"a.svg"(Width 256).pad 1.02.c.lwG 0.012.fst.d.words

The program reads the instructions as one line from stdin, if this is unacceptable let me know.

Compiles into a program that takes in flags -w width -h height -o outputfile. Outputs an "a.svg" file, if that's not immediately clear from the code. Since the output is a vector image, it's not 'pixel perfect'.

This is my first time working with Diagrams -package, feel free to point out any mistakes I made. Especially any backend that would let me output with less code would be nice.

You can see some of the first steps I took when developing the code in http://paste.hskll.org/get/1737. It differs from the code above in imports and lacks main since the paste.hskll.org provides its own main and drawing environment.

shiona

Posted 2014-10-31T04:50:56.387

Reputation: 2 889

2

Python - 434 405 377 364 361

My first python golf. This can probably be improved A LOT, so any feedback is appreciated.

from turtle import*
a=[[1,1,254,254]]
for c in input().split():
 v,w,x,y=a.pop();p,b,f,g=int(c[1::1]),'hvc'.index(c[0]),x-v,y-w
 if b>1:goto(v,-w),color('#000',['#fff','red','#00f','#ff0'][p-1]),begin_fill(),[(fd(o),rt(90))for o in[f,g]*2],end_fill()
 else:a+=[[v,w,(x,v+(((x-v)/100)*p))[b],(w+(((y-w)/100)*p),y)[b]])],a+=[[[v,a[-1][2]][b],[a[-1][3],w][b],x,y]]

William Barbosa

Posted 2014-10-31T04:50:56.387

Reputation: 3 269

1You can save a char by merging lines 4, 5 with a semicolon. Also a+=[x] instead of a.append(x). And split doesn't need an argument if separating by whitespace. – Sp3000 – 2014-11-05T00:59:48.613

1

HTML + JavaScript ES6 (407)

Tested with Firefox 32.0.3

<canvas id=c width=256 height=256><script>r=[[1,1,253,253]]
p=x=>r.push(x)
o=c.getContext("2d")
o.lineWidth=3
prompt().split(" ").map(x=>{q=r.pop()
v=q[0]
b=q[1]
n=q[2]
m=q[3],{c:x=>{o.beginPath()
o.rect(v,b,n,m)
o.fillStyle=[,"#fff","red","blue","#ff0"][x]
o.fill()
o.stroke()},v:x=>{s=x/100*n|0
p([v,b,s,m])
p([v+s,b,n-s,m])},h:x=>{s=x/100*m|0
p([v,b,n,s])
p([v,b+s,n,m-s])}}[x[0]](+x.slice(1))})</script>

Mika Lammi

Posted 2014-10-31T04:50:56.387

Reputation: 1 151

1So much more golfable! x.charAt(0) -> x[0]; x.substr -> x.slice; white yellow -> #fff #ff0; document.getElementById("c") -> c ... and more – edc65 – 2014-11-02T22:36:39.557

@edc65 Thanks! I'll improve it further tomorrow. – Mika Lammi – 2014-11-02T23:04:25.020

Thanks for the answer, but I try to test it and I have a white screen? – Arnaud – 2014-11-03T02:14:54.370

@SuperChafouin What browser are you using? I don't think that arrow functions (and other ES6 stuff) are really supported except in Firefox. – Mika Lammi – 2014-11-03T06:18:45.200

1

HTML+JavaScript (ES6) 335

Too similar to @mika answer - marking CW.

  • replace with function instead of split...map
  • spread operator
  • push 2 values at once
  • ternary operator instead of function properties

<canvas id=c><script>
c.width=c.height=256,
s=[[1,1,253,253]],
o=c.getContext('2d'),
o.translate(0.5,0.5), // to avoid anti-alias on straight lines
o.lineWidth=3,
prompt().replace(/(\S)(\d+)/g,(_,c,n)=>(
p=s.pop(o.fillStyle=[,'#fff','red','#00f','#ff0'][n]),
c<'d'?(o.fillRect(...p),o.strokeRect(...p))
:(c=c<'i'|2,
 q=[...p],
 q[c]=r=q[c]*n/100|0,
 p[c]-=r,
 p[c-2]+=r,
 s.push(q,p))))
</script>

edc65

Posted 2014-10-31T04:50:56.387

Reputation: 31 086