13
\$\begingroup\$

Can you write a program that renders to screen a group of pixels exploding apart (as in a simple particle engine) and can you do this in any remarkably small number of characters (key strokes)? (Recall the game lemmings, when those little guys would explode and their little pixel pieces fly apart.)

Someone programmed a simple particle system here as a Processing sketch and it is pretty hefty compared to what I think others should be able to accomplish if they tried. But I'd be much more impressed if it someone could do the same in c++ and sdl, or even java or c#.

\$\endgroup\$
5
  • 2
    \$\begingroup\$ "Lines of code" is a metric that opens a lot of ambiguity, and is certainly not [code-golf] which is "number of characters" or sometimes "number of bytes". Related discussion on meta. \$\endgroup\$ Commented May 13, 2011 at 15:32
  • 4
    \$\begingroup\$ BTW--The issue I raised above, and the rather incomplete specification are things that could have been usefully hammered out by discussing this in advance in the Puzzle Lab chat or the Sandbox on meta. But, in any case, welcome to CodeGolf.SE. \$\endgroup\$ Commented May 13, 2011 at 15:38
  • \$\begingroup\$ Updated question, replaced LOC with number of characters. \$\endgroup\$ Commented May 13, 2011 at 15:48
  • 1
    \$\begingroup\$ yeah, if you write C/C++/Java/Any C derivative you could write an entire OS in 1 line of code \$\endgroup\$ Commented May 13, 2011 at 18:00
  • \$\begingroup\$ Related: stackoverflow.com/questions/1947031/… \$\endgroup\$
    – gnibbler
    Commented May 14, 2011 at 10:12

12 Answers 12

13
\$\begingroup\$

Python, 245 chars

import random,time
R=lambda:random.randrange(-999,999)/1e3
P=[(40+20j,R()+1j*R())for i in' '*20]
for i in' '*20:
 C=([' ']*80+['\n'])*40
 for p,v in P:C[int(p.real)+81*int(p.imag)]='*'
 print''.join(C);P=[(p+v,v*.95)for p,v in P];time.sleep(.1)
\$\endgroup\$
1
  • \$\begingroup\$ It's no lemming explosion, but definitely a +1 for brevity! \$\endgroup\$ Commented May 19, 2011 at 4:46
10
\$\begingroup\$

C#, WPF – 1523

Not terribly serious; this was mainly an attempt whether it actually worked.

What I'm doing here is using an ItemsControl (Menu, since it's shorter) in WPF to display particles via data binding and templating. A data template controls how the particles look like (in this case a simple circle) and data binding controls color and position of the particles.

Each particle has a position, a color and a direction which get updated by a timer. Initially a bunch of particles are generated in the center of the window with (normal-distributed) random directions. That collection gets data-bound to the ItemsControl which then handles displaying the particles automatically, whenever the properties are updated. Particles are dragged down a bit due to gravity.

It got a little lengthy, admittedly. But at least it looks nice:

enter image description here

It can surely be made shorter by omitting:

  • gravity, causing particles to expand uniformly to all sides;
  • the normal distribution for the initial vectors, causing the particles to expand in a sparse »box«;
  • the brightness variation, leaving particles black.

I opted not to do so in the interest of aesthetics. This solution is way longer than almost anything else regardless. The data-binding and templating approach might be elegant but it's also quite verbose compared with simply updating a bitmap. (Note: I got it down to 1356 by leaving all of the above out, but it looks horrible then.)

The code is distributed in three files, which are given here in formatted form for legibility:

App.xaml

<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" StartupUri="W.xaml"/>

W.xaml

<Window x:Class="W" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Menu Name="i">
        <Menu.ItemTemplate>
            <DataTemplate>
                <Ellipse Width="2" Height="2" Fill="#000" Opacity="{Binding O}">
                    <Ellipse.RenderTransform>
                        <TranslateTransform X="{Binding X}" Y="{Binding Y}"/>
                    </Ellipse.RenderTransform>
                </Ellipse>
            </DataTemplate>
        </Menu.ItemTemplate>
        <Menu.Template>
            <ControlTemplate>
                <ItemsPresenter/>
            </ControlTemplate>
        </Menu.Template>
        <Menu.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas/>
            </ItemsPanelTemplate>
        </Menu.ItemsPanel>
    </Menu>
</Window>

W.xaml.cs

using M = System.Math;
using T = System.Timers.Timer;
using System;
using System.ComponentModel;

partial class W
{
    int a;
    T t = new T(99);

    public W()
    {
        InitializeComponent();
        Height = Width = 500;
        var r = new Random();
        Func<double> n = () => 2 * (M.Sqrt(-2 * M.Log(r.NextDouble())) * M.Sin(6 * r.NextDouble()));
        var l = new System.Collections.Generic.List<P>();
        for (; a++ < 300; )
            l.Add(new P { X = 250, Y = 250, f = n(), g = n() });
        i.ItemsSource = l;
        t.Elapsed += delegate
        {
            foreach (P x in l)
            {
                x.X += x.f;
                x.Y += x.g += .2;
                x.O = M.Max(1 - M.Sqrt(M.Pow(250 - x.X, 2) + M.Pow(250 - x.Y, 2)) / 250, 0);
            }
        };
        t.Start();
    }
}

class P : System.Windows.ContentElement, INotifyPropertyChanged
{
    public double y, f, g;
    public double X { get; set; }
    public double O { get; set; }
    public double Y
    {
        get { return y; }
        set
        {
            y = value;
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(""));
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
}
\$\endgroup\$
5
  • 1
    \$\begingroup\$ +1 Great looking example! Much like those classic exploding lemmings of days gone by. And I think this beats the Processing code in the initial Question. \$\endgroup\$ Commented May 17, 2011 at 6:43
  • \$\begingroup\$ @icnivad: I have to admit that the Processing sketch (I only looked at the final result, not the code) was my inspiration for the looks. \$\endgroup\$
    – Joey
    Commented May 17, 2011 at 8:09
  • \$\begingroup\$ Gah! I stop golfing this, now. It has some nice tricks in it by now (such as the PropertyChanged for all properties and only on the last one that is set). Given that I started out above 2000 characters, I guess a 500-char reduction isn't too bad. It also got quite slow by now. DispatcherTimer works much better than Timer, but is way longer. I might be tempted to port this to Silverlight and run it on my phone, though. \$\endgroup\$
    – Joey
    Commented May 17, 2011 at 10:59
  • \$\begingroup\$ I think this is the one to beat for the combination of code size and aesthetic quality of the explosion. \$\endgroup\$ Commented May 17, 2011 at 19:32
  • \$\begingroup\$ icnivad: I'll rewrite the whole thing to paint directly on a bitmap later; it should be much shorter, then. 45 % of the code are XAML; a large portion of code goes into being able to bind UI elements to the particle properties. Add to that the general verbosity of C# and it's way more verbose than it'd need to be. \$\endgroup\$
    – Joey
    Commented May 17, 2011 at 19:34
7
\$\begingroup\$

postscript - 287 244 chars

currentpagedevice/q{exch def}def/PageSize get/z{dup 3 1 roll add exch 4 2 roll}def{2
div}forall/y/r{rand 2 27 exp div 8 sub}def q/x q[99{[x r y r]}repeat]50{dup{aload/t q
3 index 2 index 4 4 rectfill 1 sub z z t astore pop}forall showpage}repeat

run with gs -dNOPAUSE asplode.ps

You could even print it out and make a flipbook

\$\endgroup\$
1
  • \$\begingroup\$ Wonderful! It's beautiful! \$\endgroup\$ Commented May 23, 2012 at 12:04
5
\$\begingroup\$

Javascript - 268 chars

Here's a 1 dimensional, 2 particle, explosion:

javascript:d=document;c=d.createElement('canvas');d.body.appendChild(c);g=c.getContext("2d");function e(x,y,m){g.arc(x,y,m,0,2*Math.PI,false);g.fill()}function s(a,b,v,t){c.width=c.width;e(50+t*v,50,b);e(50+t*b*v/(b-a),50,a-b);setTimeout(function(){s(a,b,v,t+1)},100)};s(9,5,1,0)

To run it, open an about:blank page in a good web browser, paste into the url bar and press enter. You can modify the explosion by editing the values at the end in s(10,5,1,0). The first value is the size of the particle that is exploded. The second value is the size of the particle that is exploded out of it. The third value is the speed of the particle exploded out of it. Leave the '0' as it is.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ This does not work in Safari 5.0.5 (shows something that looks a bit like a baseball bat) or in Chrome 11.0.696.68 (shows two balls, one slightly larger than the other, moving apart slowly). \$\endgroup\$
    – marinus
    Commented May 13, 2011 at 20:46
  • 1
    \$\begingroup\$ @marinus what's happening in Chrome is what's supposed to be happening. \$\endgroup\$
    – david4dev
    Commented May 13, 2011 at 21:20
  • \$\begingroup\$ Can't get it to work on FF4, IE8. :( \$\endgroup\$
    – st0le
    Commented May 18, 2011 at 5:46
  • \$\begingroup\$ Well I tested it on Firefox 4.0.1 and Chromium 11.0.696.65. Make sue you copied the whole script - I find its easy to miss out the end bracket when copying. \$\endgroup\$
    – david4dev
    Commented May 18, 2011 at 8:56
  • \$\begingroup\$ @st0le IE8 does not support the canvas tag, unless you perform some dirty tricks: stackoverflow.com/questions/1332501/… \$\endgroup\$ Commented May 22, 2012 at 8:48
4
\$\begingroup\$

APL (120 118)

It has the same kind of output as the Python entry (i.e. it just outputs the states on a character grid). Only the grid is 30x15 and the particle origin is at 15x7.

⍎⊃,⌿(9⍴⊂'(⎕DL.1)⊢{{(A+2↑⍵),0.95×A←2↓⍵}¨⍵⊣⎕←'' ⍟''[1+(⍳15 30)∊2↑¨⌊⍵]}'),⊂',⌿⍉10 4⍴⍎''⍬'',420⍴'',(7 15,.01×99-?2⍴199)'''
\$\endgroup\$
2
\$\begingroup\$

JavaScript 502 500 496

This is a combination of the Joey's and david4dev's answers (it's a shameless copy of Joey's algorithm implemented using Javascript/canvas ☺):

W=500;H=250;function r(){return 2*m.sqrt(-2*m.log(m.random()))*m.sin(6*m.random())}function n(){z=[];for(i=W;i;i--){s={};s.x=s.y=H;s.f=r();s.g=r();z.push(s)}}function w(){x.clearRect(0,0,W,W);z.forEach(function(a){a.x+=a.f;a.y+=a.g+=.2;x.fillStyle="rgba(0,0,0,"+m.max(1-m.sqrt(m.pow(H-a.x,2)+m.pow(H-a.y,2))/H,0)+")";x.fillRect(a.x,a.y,2,2)})}z=[];m=Math;d=document;c=d.createElement("canvas");c.width=c.height=W;d.body.appendChild(c);x=c.getContext("2d");n();setInterval(n,2e3);setInterval(w,10)

JSFiddle preview: http://jsfiddle.net/GVqFr/60/ (you can press the TidyUp button to format the code nicely)

\$\endgroup\$
2
  • \$\begingroup\$ I'm not javascript expert, but you use the constant 500 a lot. If you can define a global variable a=500, you can save a few characters by replacing all 500 with a. \$\endgroup\$
    – Mr. Llama
    Commented Oct 1, 2013 at 21:31
  • \$\begingroup\$ @GigaWatt you're right; that worked for 250 as well. \$\endgroup\$ Commented Oct 1, 2013 at 21:39
1
\$\begingroup\$

Bash 380

C="4443311177"
t=".-xxXMXxx-."
alias c='echo -e "\e[2J"'
g(){
echo -e "\e[1;$4\e[$2;$1H$3"
}
f(){
x=$1
y=$2
p=$((2-RANDOM%5))
q=$((2-RANDOM%5))
for i in {-5..5}
do
x=$((x+p))
y=$((y+q))
n=$((5+i))
c=$((5+i))
g $x $y ${t:n:1} 3${C:c:1}m 
w=$(printf "%04i\n" $((5*i*i)))
sleep ${w/0/0.}
g $x $y " " 3${C:c:1}m
done
}
e(){
c
for i in {1..10}
do
f $((COLUMNS/2)) $((LINES/2)) &
done
}

Call e like explode.

update: colorized

t=text, c=cls, g=gotoxy, f=fly, C=COLOR

\$\endgroup\$
1
\$\begingroup\$

C with SDL, 423 chars

Since the original problem description explicitly mentioned SDL, I felt it was past time that an SDL solution was submitted. Unfortunately, the names of the SDL function and structs aren't particularly terse, so this program is a little long. In fact, I can't even leave out the #include.

#include<math.h>
#include"SDL.h"
SDL_Surface*s;SDL_Event e;SDL_Rect p;int i,n;double q[256];main(){
SDL_Init(SDL_INIT_VIDEO);s=SDL_SetVideoMode(320,320,32,0);
for(srand(time(0));e.type-SDL_QUIT;n=-~n%64){
for(i=256*!n;i;q[--i]=rand()%65536*9.5874e-5);
for(SDL_FillRect(s,0,i=0);++i<256;SDL_FillRect(s,&p,-n*67372036))
p.x=160+cos(q[i])*q[i-1]*n,p.y=160+sin(q[i])*q[i-1]*n,p.w=p.h=1;
SDL_Flip(s);SDL_Delay(50);SDL_PollEvent(&e);}}

(Since the code is already so huge, I left in some extra bits so that it would compile without warnings. I miss compiling without warnings sometimes. Removing them would save about 30 or so chars.)

The animation runs in an infinite loop. Close the window to exit the program. Each explosion uses a new set of random particles.

I would also like to point out the number67372036 in the code. It appears in the expression for the last argument in the second call to SDL_FillRect(). As the code stands, the explosion is rendered entirely in grays. Changing this number slightly will add a very subtle but pleasant color effect to the explosion. The number 67372032 colors the particles at the start of the explosion, while the number 67372034 provides a color effect as they fade out at the end. Other numbers can produce less subtle color-cycling effects. I encourage you to try them out.

\$\endgroup\$
1
\$\begingroup\$

After seeing some of the other great examples here, I decided to give it a go, and make a particle function that fits in 140byt.es

Javascript, 282 chars

(138 chars particle function and 150 chars basic canvas drawing boilerplate)

p=function(a,t,x,y,n,g,s,i,d){with(Math)for(i=n;i--;d=cos(i*sin(i*s)),a.globalAlpha=n/t/i,a.fillRect(x+t*sin(i)*d, y+t*cos(i)*d+t*g,2,2));};d=document;a=d.body.appendChild(d.createElement('canvas')).getContext('2d');t=setInterval("a.clearRect(0,0,300,150);p(a,t++, 50,50,1e3,.2,1)")

Live JSFiddle example here

By making the code fully procedural I no longer needed any array or object-assignment code, reducing the size a lot. Making a procedural effect also has some other nice side-effects.

The code could be made smaller by ommitting Gravity, Seeds, Number of Particles, etc, but I think these features are too nice to remove ;).

Features

  • Configurable X,Y center of explosion.
  • Configurable number of particles
  • Gravity in the vertical direction: Have your particles fall down or fly up!
  • Seedable, each seed has its own explosion and will show exactly that explosion each time, across computers.
  • Slowmotion, Fast Forward and playing explosions Backwards is all possible, due to the procedural way the effect is created.
  • Size:138 bytes.

Also check it out on GitHub, for an annotated version.

\$\endgroup\$
0
\$\begingroup\$

Python with PyGame, 240 chars

I realize that there is already a solution in python, but since that one just prints characters, I thought it would be worthwhile to make one that draws a nice animation.

Ungolfed, what I started with:

import math
import random
import pygame
pygame.init()

screen = pygame.display.set_mode((800, 800))
particles = [(random.gauss(0,.5), random.uniform(0,6.28318)) for i in range(2000)]

for i in range(399):
    screen.fill((255,255,255))
    for speed, angle in particles:
        distance = i * speed
        x = 400 + distance * math.cos(angle)
        y = 400 + distance * math.sin(angle)
        screen.set_at((int(x), int(y)), (0,0,0))
    pygame.display.flip()

After much hackery. Fullscreen to save some characters. Not using sound or fonts, so I think init() is unnecessary (it works for me).

import math as m,random,pygame
d,x,g=pygame.display,range(999),random.gauss
s,e=d.set_mode(),[(g(0,.2),g(0,9))for i in x]
for i in x:
 d.flip(),s.fill([255]*3)
 for v,a in e:
        y=400+i*v*m.cos(a),400+i*v*m.sin(a)
        s.set_at(map(int,y),[0]*3)
\$\endgroup\$
0
\$\begingroup\$

Python -- 327 chars

Intresting things:

  • Use complex number as 2D vector
  • (v * cos(a), v * sin(a)) implemented as v*e**(1j*a)
  • Looks like a 3D explosion.
  • Gravity.

.

import pygame as P,random as R,math
R=R.random
D=P.display
D.init()
W=800
S=D.set_mode((W,W))
T=P.time.Clock()
C=lambda v:map(int,(v.real,v.imag))
X=[(8+R())*math.cos(R()*1.57)*2.7**(1j*R()*6.28) for i in range(999)]
for t in range(250):
 D.flip();T.tick(30);S.fill(2**24-1)
 for v in X:S.set_at(C(v*t+.005j*t*t+W/2*(1+1j)),0)
\$\endgroup\$
0
\$\begingroup\$

dwitter 112

c.width^=0
t?o.push({X:1e3,Y:500,U:S(99*t),V:C(9*t)}):o=[]
o.map(a=>{a.X+=a.U,a.Y+=a.V,x.fillRect(a.X,a.Y,9,9)})

try it out by copy/pasting the code to dwitter.net

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.