Short drawing programme

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.

• 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? Commented Nov 20, 2014 at 22:40
• Some 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. Commented Nov 20, 2014 at 22:53
• @Quincunx I have put a Q & A in the question tell me if it is ok now. Commented Nov 21, 2014 at 10:28
• 1. 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.) Commented Nov 21, 2014 at 12:24
• 1. "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? Commented Nov 21, 2014 at 14:29

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).

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.

• Freehand also gives you the bonus. Commented Nov 22, 2014 at 19:29
• @Caridorc: Ah, great. I will update my answer then.
– Emil
Commented Nov 22, 2014 at 21:13
• That's going to be hard to beat. Commented Nov 23, 2014 at 9:41
• if(key>0) is shorter than if(keyPressed) Commented Feb 12, 2017 at 17:42

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. •$(document).ready in codegolf? Commented Nov 21, 2014 at 15:48
• you don't need the quotes for id= and maybe others too (haven't done html in a while) Commented Sep 2, 2017 at 6:15

Python 2.7 - 339197 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 2:

• I now have a file on my computer named ms-paint.py. Commented Nov 22, 2014 at 15:09
• Enjoy 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... Commented Nov 22, 2014 at 15:50

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();}}


using System;
using System.Drawing;
using System.Windows.Forms;

class f : Form
{
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.

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)
}
]


• Can this draw lines from point to point? It appears to allow free hand drawing only. Commented Nov 22, 2014 at 12:14
• @githubphagocyte Yeah, free hand only at the moment. Commented Nov 22, 2014 at 12:32
• @githubphagocyte Added a straight line option Commented Nov 22, 2014 at 12:47
• best answer thus far. Commented Nov 22, 2014 at 14:32
• I love the drawing though. Commented Nov 22, 2014 at 15:46

= 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:

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

#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


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


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()


APL (dzaima/APL), 65 bytes, no bonuses

P5.size←2⌿600
P5.draw←{P5.LM.p:P5.G.ln P5.mx P5.my P5.pmx P5.pmy}


A straightforward port of the existing processing answer.

Explanation

P5.size←2⌿600                                        set canvas to 600x600 pixels
P5.draw←{                                         } do the following every frame:
P5.draw←{P5.LM.p:                                 } if the mouse is held down:
P5.G.ln                            draw a line from
P5.mx P5.my                current mouse position
P5.pmx P5.pmy  to previous mouse position

• I think this is currently the best score here. Well done! :D
– Dion
Commented Nov 9, 2020 at 16:14
• @Dion a̶n̶d̶ ̶t̶h̶e̶ ̶m̶o̶s̶t̶ ̶l̶o̶w̶ ̶e̶f̶f̶o̶r̶t̶ ̶o̶n̶e̶ Commented Nov 9, 2020 at 16:15
• as it often is with codegolf :p
– Dion
Commented Nov 9, 2020 at 16:16