Short drawing programme

13

2

You just invited a liberal arts major to your house and you're telling him/her

"You know, I am a great programmer and I can do x and y and z..."

S/he quickly gets bored and asks you:

"If you really are a great programmer, can you make a programme to let me draw, I just need to draw lines on the screen by using the mouse, and selecting different colours in any manner".

Your code may import standard libraries. Your code may require the colours to be selected via the keyboard.

This is ; shortest code wins.

Bullet points

  • The lines are drawn by moving the mouse around while pressing the left button.

  • Bresenham's Line Algorithm is not necessary any built-in algorithm will do the trick

  • If the user can change the line thickness in any way you get a * 0.8 bonus but it is not obligatory.

  • I guess it should be nicer to implement the line-drawing ourselves, but if you want you can import a library for that just say it in the code description.

  • The minimum is 5 different colours (red,green,blue,white,black). If you make them change randomly you get a penalty of *1.2. You may change them in any way you may want (both buttons and key presses are OK).

  • Drawing them pressing the mouse between to points or freehand would be best (i.e. as you do in paint) and gives you a bonus of *0.7 , but any other method is okay: (example) click two points and draw a line between those points?

  • The drawing canvas has to be 600x400

  • Changing the colour should change the colour only of the lines that will be drawn in the future.

  • Implementing a "Clear All " command is not obligatory but if you implement that you get *0.9 bonus.

Caridorc

Posted 2014-11-20T22:28:09.180

Reputation: 2 254

Doesn't *0.8 reduce original score to 80%? – Tomáš Zato - Reinstate Monica – 2016-02-02T13:01:17.063

2

How are lines required to be drawn? Bresenham's Line Algorithm? Do the lines need to be variable thickness? Do we need to implement the line-drawing ourselves? Please specify more. And it is normally assumed that our code may "import standard libraries". How many colors must be choosable? Is 2 okay? Or how about randomly choosing color every time a keyboard button is pressed?

– Justin – 2014-11-20T22:40:02.547

2Some more clarifications needed: How are the lines drawn? Do you click two points and draw a line between those points? How big does the drawing canvas have to be? How many colors must be supported? Can changing the color also change the color of every other line? Etc. This challenge is currently very underspecified. – Doorknob – 2014-11-20T22:53:02.847

@Quincunx I have put a Q & A in the question tell me if it is ok now. – Caridorc – 2014-11-21T10:28:54.457

2>

  • Please condense the Q&A. Eliminate the Questions and make the Answers stand on their own as bullet points. Note that comments can sometimes get deleted. The Bresenham's Algorithm Point does not make any sense without reading the comment. I assume what you are saying is that Bresenham's algorithm is not required and any algorithm or standard/library function will do. 2. Ultimately winning depends on in what language it is easy to get into the API and access the Right button (instead of the usual left button.)
  • < – Level River St – 2014-11-21T12:24:59.520

    @steveverrill I made an error "while clicking the left button" – Caridorc – 2014-11-21T12:29:36.547

    2>

  • "Drawing them pressing the mouse between 2 points is best but any other method is ok" What about freehand drawing like with the pencil tool in paint? I suggest you make it clearer, or eliminate the "any other method is ok" altogether. 2. The method of changing colour should be better specified. For example, can it be done from the keyboard, by rotating through the colours with the other mouse button, or does it have to be by clicking an on-screen pallete?
  • < – Level River St – 2014-11-21T14:29:52.897

    The currently accepted answer does not implement drawing in white. Does the question need to be changed to make clear that the listed colours (red,green,blue,white,black) are not required, and it is only the number of colours which counts, or does the accepted answer need to have its score adjusted for not providing all of the required colours? – trichoplax – 2014-11-22T12:08:52.873

    @githubphagocyte if you like, you may switch purple for white, and save a byte in the process. There are shorter solutions now anyway; the accepted answer should be changed. – primo – 2014-11-22T14:39:00.310

    Answers

    9

    HTML + jQuery + CSS - 507 x (0.7 x 0.8 x 0.9) = 255.528

    Not as short as I thought it would be, but I like the result.

    Features:

    • Click-and-drag drawing mode. (0.7)
    • Seven colors (black + rainbow).
    • Variable brush width (slider control). (0.8)
    • Clear all function. (0.9)

    Live Demo: http://jsfiddle.net/onsLkh8y/9/


    HTML - 84 bytes

    <input id="r" type="range" min="1" max="9"><canvas id="c" width="600" height="400"/>
    

    CSS - 35 bytes

    #c{border:1px solid;cursor:pointer}
    

    jQuery - 388 / 446 bytes

    W3C compliant browsers (e.g. Chrome) - 388 bytes

    var t=c.getContext('2d');$.each('black0red0orange0yellow0green0blue0purple0clear'.split(0),function(k,v){
    $(r).before($('<button>'+v+'</button>').click(function(){k>6?t.clearRect(0,0,600,400):t.strokeStyle=v}))})
    $(c).mousedown(function(e){t.lineWidth=$(r).val();t.beginPath();t.moveTo(e.offsetX,e.offsetY)})
    .mousemove(function(e){if(e.which==1){t.lineTo(e.offsetX,e.offsetY);t.stroke()}})
    

    Cross-Browser version (fixes for Firefox, Safari, IE) - 446 bytes

    var t=c.getContext('2d');$.each('black0red0orange0yellow0green0blue0purple0clear'.split(0),function(k,v){
    $(r).before($('<button>'+v+'</button>').click(function(){k>6?t.clearRect(0,0,600,400):t.strokeStyle=v}))})
    var d,p=$(c).offset();$(c).mousedown(function(e){d=t.lineWidth=$(r).val();t.beginPath()t.moveTo(e.pageX-p.left,
    e.pageY-p.top)}).mousemove(function(e){if(d){t.lineTo(e.pageX-p.left,e.pageY-p.top);t.stroke()}}).mouseup(function(){d=0})
    

    Fixes:

    • FireFox - event.offset[X|Y] are undefined.
    • Safari - event.which and event.buttons are not meaningfully defined on mousemove.
    • Internet Explorer - works with both of the above fixes, although using e.buttons would have been sufficient.

    primo

    Posted 2014-11-20T22:28:09.180

    Reputation: 30 891

    you don't need the quotes for id= and maybe others too (haven't done html in a while) – Cyoce – 2017-09-02T06:15:24.563

    1$(document).ready in codegolf? – edc65 – 2014-11-21T15:48:24.210

    10

    Processing - 93 · 0.9 = 83.7

    With next to no overhead for drawing, but a very verbose syntax, in Processing the best score is probably reached without any nice features and only one bonus:

    void setup(){
    size(600,400);
    }
    void draw(){
    if(mousePressed)line(mouseX,mouseY,pmouseX,pmouseY);
    }
    

    Score: 93 · 0.9 = 83.7 (Newlines are for readability only and are not counted in the score.)

    However, it's much more fun with all the bonuses in place:

    void setup(){
    size(600,400);
    }
    int i,x,y;
    void draw(){
    stroke(7*i%256,5*i%256,i%256);
    strokeWeight(i%9);
    if(keyPressed)i++;
    if(!mousePressed){x=mouseX;y=mouseY;if(x<0)background(0);}
    }
    void mouseReleased(){
    line(x,y,mouseX,mouseY);
    }
    

    Score: 221 · 0.8 · 0.7 · 0.9 = 111.4

    It's used like this:

    • Click and drag the mouse to draw a straight line.

    • While clicked, drag the mouse off the left side of the window and release the mouse button to clear the screen.

    • Holding down any key will cycle through the red, green and blue values of the drawing colour and through different stroke thicknesses. Since the cycling periods are different, practically all combinations can be reached (with a bit of trying).

    colourful output 1

    Edit:

    Since freehand drawing gives the 0.7 bonus as well, here is yet another solution:

    void setup(){
    size(600,400);
    }
    int i;
    void draw(){
    stroke(7*i%256,5*i%256,i%256);
    strokeWeight(i%9);
    if(keyPressed)i++;
    if(key>9)background(0);
    if(mousePressed)line(mouseX,mouseY,pmouseX,pmouseY);
    }
    

    Score: 188 · 0.8 · 0.7 · 0.9 = 94.8

    It's used like this:

    • Click and drag to draw freehand lines.

    • Hold the tab key to change the colour and stroke thickness. This can also be done while drawing (see picture).

    • Hit any key but tab and then tab to clear the screen.

    colourful output 2

    Emil

    Posted 2014-11-20T22:28:09.180

    Reputation: 1 438

    if(key>0) is shorter than if(keyPressed) – user41805 – 2017-02-12T17:42:46.623

    Freehand also gives you the bonus. – Caridorc – 2014-11-22T19:29:00.137

    @Caridorc: Ah, great. I will update my answer then. – Emil – 2014-11-22T21:13:05.480

    2That's going to be hard to beat. – primo – 2014-11-23T09:41:14.683

    9

    Python 2.7 - 339 197 324 * (0.7 * 0.8 * 0.9) = 163

    Edit: I discovered pygame can draw lines with variable width so here is an update.

    An experiment in using the PyGame modules.

    A simple paint program that draws lines from the MOUSEDOWN event (value 5) to the MOUSEUP event (value 6). It uses the pygame.gfxdraw.line() function. Pressing the TAB key will cycle through 8 colours. Pressing the BACKSPACE key will clear the display to a carefully crafted paper white colour. The ENTER key will cycle the brush size through 0-7 pixels in width.

    I am new at code-golf so I may have missed some methods of reducing the code size.

    import pygame as A,pygame.draw as G
    P=A.display
    D=P.set_mode((600,400))
    C=(0,255)
    S=[(r,g,b) for r in C for g in C for b in C]
    w=n=1
    while n:
     e=A.event.wait()
     t=e.type
     if t==12:n=0
     if t==2:
      if e.key==9:n+=1
      if e.key==13:w+=1
      if e.key==8:D.fill(S[7])
     if t==5:p=e.pos
     if t==6:G.line(D,S[n%8],p,e.pos,w%8)
     P.flip()
    

    Sample picture 1:

    Terrible picture of an aircraft

    Sample picture 2:

    Landscape

    Logic Knight

    Posted 2014-11-20T22:28:09.180

    Reputation: 6 622

    9I now have a file on my computer named ms-paint.py. – primo – 2014-11-22T15:09:18.693

    1Enjoy the speed and clean GUI. How MS-Paint was meant to be. I hope I don't get sued by a certain large software company... – Logic Knight – 2014-11-22T15:50:49.150

    5

    C# 519 x 0.7 x 0.8 x 0.9 = 261.6 Using the DrawLine method.

    Golfed:

    using System;using System.Drawing;using System.Windows.Forms;class f:Form{[STAThread]static void Main(){f F=new f{Width=600,Height=400};Point s=default(Point);sbyte[]c={0,0,0,1};F.MouseDown+=(_,e)=>{s=new Point(e.X,e.Y);};F.MouseUp+=(_,e)=>{F.CreateGraphics().DrawLine(new Pen(Color.FromArgb(255,c[0],c[1],c[2]),c[3]),s.X,s.Y,e.X,e.Y);};F.KeyPress+=(a,e)=>{unchecked{switch(e.KeyChar){case'r':c[0]++;break;case'g':c[1]++;break;case'b':c[2]++;break;case't':c[3]++;break;case'c':F.Invalidate();break;}}};F.ShowDialog();}}
    

    Readable:

    using System;
    using System.Drawing;
    using System.Windows.Forms;
    
    class f : Form
    {
        [STAThread]
        static void Main()
        {
            f F = new f { Width = 600, Height = 400 };
            Point s = default(Point);
            sbyte[] c = { 0, 0, 0, 1 };
            F.MouseDown += (_, e) => { s = new Point(e.X, e.Y); };
            F.MouseUp += (_, e) => { F.CreateGraphics().DrawLine(new Pen(Color.FromArgb(255, c[0], c[1], c[2]), c[3]), s.X, s.Y, e.X, e.Y); };
            F.KeyPress += (a, e) =>
            {
                unchecked
                {
                    switch (e.KeyChar)
                    {
                        case 'r': c[0]++; break;
                        case 'g': c[1]++; break;
                        case 'b': c[2]++; break;
                        case 't': c[3]++; break;
                        case 'c': F.Invalidate();break;
                    }
    
                }
            };
            F.ShowDialog();
        }
    }
    

    By holding r, g or b on your keyboard it changes the color of the next line by incrementing an sbyte-array at the corresponding index. It will start at 0 again when overflowing. So this gives us plenty colors. Same goes for thickness of the line which is increased by holding t. Pressing c clears the form.

    CSharpie

    Posted 2014-11-20T22:28:09.180

    Reputation: 381

    5

    Mathematica - 333 x 0.7 x 0.8 x 0.9 = 168

    l = {}; c = Black; s = .01;
    ColorSetter@Dynamic@c
    Dynamic@s~Slider~{0, .02}
    Button["Clear", l = {}]
    "/" Checkbox@Dynamic@b
    EventHandler[
     Dynamic@Graphics@{White, Rectangle@{600, 400}, l},
     {"MouseDown" :> 
       AppendTo[l, p = {}; {c, Thickness@s, Line@Dynamic@p}], 
      "MouseDragged" :> (p = 
         Append[p, MousePosition@"Graphics"][[If[b, {1, -1}, All]]]),
      "MouseUp" :> (l[[-1, 3]] = Line@p)
      }
     ]
    

    enter image description here

    swish

    Posted 2014-11-20T22:28:09.180

    Reputation: 7 484

    Can this draw lines from point to point? It appears to allow free hand drawing only. – trichoplax – 2014-11-22T12:14:08.940

    @githubphagocyte Yeah, free hand only at the moment. – swish – 2014-11-22T12:32:41.980

    1@githubphagocyte Added a straight line option – swish – 2014-11-22T12:47:42.743

    best answer thus far. – primo – 2014-11-22T14:32:54.003

    I love the drawing though. – tomsmeding – 2014-11-22T15:46:28.850

    4

    Tcl/Tk, 252

    x 0,8 x 0,7 x 0,9

    = 127,008

    253 x 0,8 x 0,7 x 0,9= 127,512

    254 x 0,8 x 0,7 x 0,9= 128,016

    255 x 0,8 x 0,7 x 0,9= 128,52

    grid [canvas .c -w 600 -he 400]
    set c red
    incr t
    lmap k {1
    B1-Motion
    3
    MouseWheel
    2} s {{set L [.c cr l %x %y %x %y -f $c -w $t]}
    {.c coo $L "[.c coo $L] %x %y"}
    {set c [tk_chooseColor]}
    {if $t|%D>0 {incr t [expr %D/120]}}
    {.c de all}} {bind . <$k> $s}
    

    Tcl/Tk, 267

    x 0,8 x 0,7 x 0,9

    = 134,568

    grid [canvas .c -w 600 -he 400]
    set c red
    set t 0
    bind .c <1> {set L [.c cr l %x %y %x %y -f $c -w $t]}
    bind .c <B1-Motion> {.c coo $L "[.c coo $L] %x %y"}
    bind .c <3> {set c [tk_chooseColor]}
    bind .c <MouseWheel> {if $t||%D>0 {incr t [expr %D/120]}}
    bind .c <2> {.c de all}
    

    To use it:

    • Left mouse button behaves as question requests
    • The initial color is red. Right mouse shows a dialog which allows the user to choose the color which will be used the next time. Always press OK button, otherwise color will be undefined. I could fix this, but it would consume bytes
    • To adjust the thickness of the line that will be used next time, you can rotate the mouse wheel: Up=thicker, Down=thinner
    • To clear the image press the middle mouse button

    A simple test:

    enter image description here

    sergiol

    Posted 2014-11-20T22:28:09.180

    Reputation: 3 055

    2

    DarkBASIC Pro - 318 x 0.7 x 0.9 = 200.34

    The most interesting thing here is using some bitwise logic on the current keyboard scancode to change the color. I use two different bits from the scancode for each channel - so almost any 6-bit color is possible.

    • Hold down any key on your keyboard to use a color (on my American keyboard: White=F5, Black=no key, Red=2, Green=- (minus), Blue=b)
    • Right-click to clear

    Here is a compiled EXE: Download

    #constant a set current bitmap
    set display mode 800,400,32
    create bitmap 1,800,400
    do
    s=scancode()
    ink rgb((s&&3)*85,((s/4)&&3)*85,((s>>4)&&3)*85),0
    m=mousex()
    n=mousey()
    o=mouseclick()
    if o*(d=0) then d=1:x=m:y=n
    a 1
    if (o=0)*d then d=0:line x,y,m,n
    if o=2 then cls
    a 0
    cls
    copy bitmap 1,0
    if d then line x,y,m,n
    loop
    

    BMac

    Posted 2014-11-20T22:28:09.180

    Reputation: 2 118

    1

    BBC BASIC - 141 no bonuses

    My first programming language and generally never used by me anymore :)

    SYS "SetWindowPos",@hwnd%,0,0,0,600,400,6:VDU 26
    1 MOUSE X,Y,b
    IF b=4 THEN GOTO 4
    GOTO 1
    4 MOUSE x,y,b
    IF b=0 THEN LINE X,Y,x,y:GOTO 1
    GOTO 4
    

    JamJar00

    Posted 2014-11-20T22:28:09.180

    Reputation: 209

    1

    Python 2.7 - 384 * .8 * .7 = 215.04

    from Tkinter import*;o=1
    a='0f';C=['#'+r+g+b for r in a for g in a for b in a]
    def i(a):global o;o+=1
    def d(a):global o;o-=1
    def I(a):global u;u+=1
    def D(a):global u;u-=1
    m=Tk();u=0;c=Canvas(width=600,height=400);c.bind("<B1-Motion>",lambda x:c.create_rectangle((x.x,x.y,x.x+o,x.y+o),fill=C[u],outline=C[u]));m.bind("q",i);m.bind("w",d);m.bind("x",D);m.bind("z",I);c.pack();mainloop()
    

    With all bonuses: 462 * .9 * .8 * .7 = 232.848

    from Tkinter import*;o=1
    a='0f';C=['#'+r+g+b for r in a for g in a for b in a]
    def i(a):global o;o+=1
    def d(a):global o;o-=1
    def I(a):global u;u+=1
    def D(a):global u;u-=1
    m=Tk();u=0;c=Canvas(width=600,height=400);c.bind("<B1-Motion>",lambda x:c.create_rectangle((x.x,x.y,x.x+o,x.y+o),fill=C[u],outline=C[u]));m.bind("q",i);m.bind("w",d);m.bind("x",D);m.bind("z",I);m.bind("m",lambda _:c.create_rectangle((0,0,602,402),fill=C[7],outline=C[5]));c.pack();mainloop()
    

    globby

    Posted 2014-11-20T22:28:09.180

    Reputation: 1 132