Blob Blame History Raw

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#define UPF 8
#define CNT 64
#define LEN 64
#define LIFE 640
typedef struct {
    unsigned seed, next;
    int p[LEN][2];
    int life;
    double dt;
} Drop;


#define W 640
#define H 480
const char imgs[] =
    "&_tC*+D*8F*7F*6G*6G*6H*5H*5H*6G*7E*9C*+C*+C*9D*9D*9F*zR*tV*qY*oZ*nZ*nX*rQ*yN*0L*1L*1K*1L*0M#GL(jM#FN(hO#CQ(fP!/U(dR!8X(bS!5b(Rc!2e(Pe!0h(Nf!xk(Lg!vo(Jh!sr(Ij!mw(Ii!kCBx(Ih!h5(Gh!fBB/(Aj!c!K'3m!Y!S'vp!"
    "U!U'us!R!W'sv!N!Z'qz!I!c'o3!E!d'n6!B!g'k9+!i'i!G1!l'U!Uz!n'R!Xw!s'N!Yv!y'G!Zu!9&8!Zu#S&n!Xw#V&k!Xw#V&l!Tz#W&l!R0#Y&k!P1#Z&263#a&308#a&3w/#b&2u!C#a&3p!H#a&2p!I#Z&3o!J#Y&4n!K#W&5n!M#T&7m!N#S&8m!N#P&+m!P"
    "#L'Am!T#E'Dn!c!3'Gn!k!D'yo#AT(Fp*Xp*Xq*Wr*Us*Tu*Px*Oz*L2*H5*F8*C/)+!C)7!F)s!U)q!X)o!Z)m!b)k!c)j!e#xn&K!f#j2&H!i#Y!C&D!k#U!G&C!u#H!N%9!y#C!V%3!0!8!t%k!0goy!w%i!2T6q!z%h#AI7o!3%f#AH7n!6%f!+H8k!/%e!8H9j#"
    "j$7!7H9i#k$7!7H+h#k$6!7I/f#l$5!8I!Ae#l$3!9J!Cc#l$0#AJ!Db#l$x#CK!Ea#h$y#AP!GY#g$w!8W!HX#d$y!ro!IW#b$t!tt!IW#Y$s!vv!IW#X$r!ww!IW#S$v!wx!IW#O$y!wy!IW#M$0!wy!HX#L$1!vz!HX#K$3!uz!FZ#J$5!uy!Db#H$9!tx!Db#G$/"
    "!tw/f#F%B!uu9h#E%D!utzr#D%F!ustx#B%I!vqn3!/%L!vpn4!9%N!wnk8!6%Q!xlg!B!2%T!ykf!E!g%o!yjd!G!d%t!yhc!J!Z%w!0eb!N!W%x!1cb!R3&N!2ab!Zi&b!4XV!rP&l!3VO(s!y)P!0)N!1)L!3)J!4)I!6)G!7)F!7!fo&+!8!aw&6#A!S7&z#E!L/"
    "&y#E!J!E&v#E!H!H&u#E!F!L&s#E!F!M&r#E!E!g&Y#E!D!k&V#E!C!o&S#E!B!t&O#E!B!4&D#E!A!+%9#F/#I%z#G+#J%x#I+#M%r#L+#N%o#N+#O%O#m+#O%K#q+#O%I#s+#O%H#t9#Q%E#v9#Q%D#w8#R%B#y8#Q%B#z7#R%A#07#R$+#26#S$7#56#S$6#65#U$"
    "5#64#V$5#63#W$6#52#X$7#4u#g$6#4p#l$8#2f#w$9#0b#0$/#yZ#2%A#xW#5%B#wV#6%I#pU#4%N#nU#3%Q#lT#2%U#jS#1%X#iS#0%a#gS#z%c#fS#x%g#dR#x%j#bR#t%p#ZR#t%w#SR#s&O!1R#q&1!QR#l&9!NS#h'F!IT#X'V!BU#W'X/X!x'79Z!r(Pqg!k("
    "YL+!X)r!K)8!B*E6*Lx*Wo'5I#bj'5M#bc'5g#Lc'5h#Lb'wu#Ia'sz#Ha'n5#Ga'j!A#Da'g!F#BZ'e!M!9Z'W!W!7Z'M!j!4Z'M!m!1Z'I!x!uY'G!3!rY'C#J!dY'A#O!aX&8#V!YX&l#t!XX&h#x!YW&d#2!XW&b#5!WW&b#6!VW&a#7!WV&a#7!WV&a#7!WV&a#"
    "6!XV&b#4!ZU&b#2!bU&c#y!fT&c#y!fT&c#v!iT&c#t!kT&c#U!+S&c#T!/S&c#S#AS&s#C#AS&4!0#CS&6!y#CS&7!x#CS&9!u#ER'D!n#FR'H!i#GR'N!c#GR'O!b#GR'i!H#GR'i!H#GR'k!F#GR'l!E#GR'm!D#GR'n!C#GR'o!B#GR'o!B#GR'o!B#GR'p!A#GR"
    "'p!A#GR'p!A#GR'p!A#GR'm!D#GR'f!K#GR'R!Y#GR'N!c#GS'J!e#HS'H!g#HT'D!j#HT'B!l#HT&+!o#HT&7!r#HU&2!u#IV&y!x#IV&v!0#IV&t!2#IV&q!5#IV&o!7#IW&j!/#IW&f#D#IX&X#I#KX&V#G#OX&U#G#PX&T#D#TX&T#A#WY&R#A#XY&Q#A#YZ&O#A"
    "#ZZ&O!8#dZ&O!6#fZ&O!2#jZ&O!1#kZ&O!z#mZ&S!u#na&z!L#pZ&4!E#rZ&97#wY'Pm#zZ'cW#1Z'hP#3a'pE#5a(Yb!zb(Vg!xa(Sl!va(Pq!uZ(Mv!sa(J1!oa(H6!lb(D!A!jb(B!V!Pb(A!W!Pc'9!Y!Pc'9!Y!Pd'8!Y!Qd'7!Y!Qd'8!X!Qd'9!W!Qe'8!W!Q"
    "e'/!T!Qe(X7!Qf(sl!Qf(1c!Qf(4Z!Qf(8V!Rf)PB!Rf*hg*gg*gh*fi*fh*fh*fil$c&djk$c&djk$c&eik$c#uD#tjj$c#sG#sjj$c#qJ#rki$c#nN#qki$c#mP#pki$c#jT#pkh$c#fZ#nkh$c#Yk#jlg$c#Ru#glg$c#C!A#dlg$c!i!k#Zl&a!r#Wm&T!0#Sn&O"
    "#B#Ko&G#K#Io&D#O#Gp&B#Q#Gp%+#U#Fp%7#X#Fq%4#a#Dr%3#c#Cs%0#f#Bs%x#j!/t%v#m!+t%u#n!+u%t#o!9u%u#n!9u%v#l!99%j#j!6!I%k#Z!q!6%M#Q!f#T%F#I!U$P$1!c!c$4$k!F!a%J$i1!N%i&Y&V%p&a%m&e%i&i%e&m%a&q%W&t%T&0%M&/%B'Q$w"
    "'T$t'X$p'a$m'd$j'i$e'j$d'p$X(u#S(0#M(8#E)J!3)R!v)a!m)h!f)n!Z)v!R)4!I*B/*L1*Rv*Vr*gg*mY;`C";

char img[H][W];
char rain[H][W];
Drop drops[CNT];


unsigned rnd(unsigned seed) { return seed*1103515245u + 12345u; }
unsigned rndu(unsigned *seed) { return *seed = rnd(*seed); }


void load() {
    const char table1[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    const char table2[] = " !#$%&'()*,-.:;<=>?@[]^_`{|}~";

    int bit = 0;
    char *d = *img, *p;
    const char *s = imgs;
    int remain = sizeof(img);
    while(*s) {
        int cnt = 0;
        while(*s && (p = strchr(table2, *s))) cnt = cnt*(sizeof(table2)-1) + (p - table2), ++s;
        cnt *= sizeof(table1)-1;
        if ((p = strchr(table1, *s++))) cnt += p - table1;
        if (cnt > remain) cnt = remain;
        memset(d, bit ? 255 : 0, cnt);
        d += cnt; bit = !bit; remain -= cnt;
    }
}


int get(int x, int y) { return img[y<0 ? 0 : y>=H ? H-1 : y][x<0 ? 0 : x>=W ? W-1 : x]; }
int get2(int x, int y, int x0, int y0) { return (x == x0 && y == y0) || get(x, y); }
void set(int x, int y) { if (x >= 0 && x < W && y >= 0 && y < H) rain[y][x] = 255; }


void dropgen(Drop* d) {
    d->dt = 0;
    d->life = 0;
    d->seed = d->next^10;
    rndu(&d->next);
    int x = rndu(&d->seed)%W;
    for(int i = 0; i < LEN; ++i) d->p[i][0] = x, d->p[i][1] = -1;
}


void dropupdate(Drop* d) {
    if (++d->life >= LIFE) return dropgen(d);
    if ((d->dt -= 1.000001) > 0) return;

    int x = d->p[0][0], x1 = x, x0 = d->p[1][0];
    int y = d->p[0][1], y1 = y;

    char lt = get(x-1, y-1);
    char t  = get(x  , y-1);
    char rt = get(x+1, y-1);
    char l  = get(x-1, y  );
    char r  = get(x+1, y  );
    char lb = get(x-1, y+1);
    char  b = get(x  , y+1);
    char rb = get(x+1, y+1);

    int ab  = !b;
    int al  = x0 >= x && !l && ((lt && t) || (lb && b));
    int ar  = x0 <= x && !r && ((rt && t) || (rb && b));
    int alb = x0 >= x && !lb && (l || b);
    int arb = x0 <= x && !rb && (r || b);

    if (!ab && !al && !ar && !alb && !arb) {
        al  = !l && ((lt && t) || (lb && b));
        ar  = !r && ((rt && t) || (rb && b));
        alb = !lb && (l || b);
        arb = !rb && (r || b);
    }

    int k = 100;
    int chance[] = { k*al, k*ar, k*alb, k*arb, 1*ab };
    for(int i = 1; i < 5; ++i) chance[i] += chance[i-1];

    int num = chance[4] ? rndu(&d->seed)%chance[4] : 1;
    if (num < chance[0]) --x1; else
    if (num < chance[1]) ++x1; else
    if (num < chance[2]) --x1, ++y1; else
    if (num < chance[3]) ++x1, ++y1; else
    if (num < chance[4]) ++y1; else y1 = H;

    memmove(d->p + 1, d->p, sizeof(d->p) - sizeof(*d->p));
    d->p[0][0] = x1;
    d->p[0][1] = y1;

    d->dt += x1 != x && y1 != y ? 1.414213562 : 1;
}


void dropdraw(Drop *d) {
    for(int i = 0; i < LEN; ++i)
        set(d->p[i][0], d->p[i][1]);
}


void update() {
    for(int i = 0; i < CNT; ++i)
        dropupdate(drops + i);
}


void draw() {
    memset(rain, 0, sizeof(rain));
    for(int i = 0; i < CNT; ++i)
        dropdraw(drops + i);
}


int main(int argc, char **argv) {
    int repeats = 0;
    unsigned seed = time(NULL);
    if (argc > 1) repeats = atoi(argv[1]);
    if (argc > 2) seed = atoll(argv[2]);

    load();
    fprintf(stderr, "vseed: %u\n", seed);
    fprintf(stderr, "vrepeats: %u\n", repeats);

    for(int i = 0; i < CNT; ++i)
        drops[i].life = rndu(&seed)%LIFE;

    unsigned seed0 = seed;
    for(int i = 0; i < CNT; ++i)
        drops[i].next = rndu(&seed);

    for(int i = 0; i < LIFE; ++i)
        update();

    int iteration = 0;
    while(1) {
        for(int i = 0; i < LIFE/UPF; ++i) {
            for(int j = 0; j < UPF; ++j) update();
            draw();
            fwrite(rain, sizeof(rain), 1, stdout);
        }
        if (repeats > 0) {
            ++iteration;
            if (iteration == repeats) break;
            if (iteration == repeats-1) {
                unsigned s = seed0;
                for(int i = 0; i < CNT; ++i)
                    drops[i].next = rndu(&s);
            }
        }
    }

    return 0;
}