Well... here's something I scribbled out this weekend. I'll probably improve it before publishing it for download (provided that the onslaught of homework would please stop)

It runs so slowly in CEmu. On my physical calc, though, it's much faster. Still stuttery, because my code in inefficient at best and straight up dysfunctional at worst.

"You're down the rabbit hole, Cemetech. The Matrix is a simulated reality. It is the most advanced calculator program ever created."

"Wait, calculator program!?"
Nice work! I’d really like to see the source for this, it’s a very well done effect. Also, was that a mouse cursor I saw at the beginning of the screenshot?
Just found a way to massively improve efficiency of this thing. Now it looks a bit better...

That mouse cursor is me with my simpleton brain using SimpleScreenRecorder and accidentally putting my cursor over the recording area... I just found out that ffmpeg can convert CEmu's animated PNGs into GIFs...

Anyway... here's the download link: https://www.cemetech.net/downloads/files/2099/x2236
Source code is included in the package.

You know what'd be fun? If you have Linux, open a TTY, log in, and run cmatrix. At the same time, run this code rain program on your graphing calculator. Then turn off the lights in your room... a true hackercave! (bonus points if the colours of the code rains match!)
Nice work Smile Took a quick look at your code; if you really wanted to improve efficiency I would recommend using the gfx_GetSpriteChar function. You could allocate all the characters you needed as sprites, and then render them rather than printing strings. Would recommend using gfx_Sprite_NoClip.
This is a really neat program! I'd love to just leave this running non-stop on my calculator Laughing

Your code is pretty neat and I was able to follow it pretty easily! However, there's always potential for cleaner code and this is what I noticed:
I highly suggest using constants to replace the many 'magic numbers' I found in your code. For example, instead of typing 40 everywhere, you could just type #define HORIZ_CHARS 40. That way your code is more readable and if you ever need to change 40 to some other number, you only have to change it in one place.
I couldn't figure out what 128 means, I assume it's the maximum number of trails you want to display at once?

A small optimization you could make is changing all your int to uint8_t or int8_t where applicable. It's slightly faster and uses less memory.

I went ahead and applied these optimizations. Although you won't notice a major speed difference, (Mateo's optimizations will speed it up more than mine) it's slightly more readable.

    the code rain from The Matrix, now on the CE

#include <tice.h>
#include <graphx.h>
#include <keypadc.h>

#define HORIZ_CHARS 40
#define VERT_CHARS 24
#define CODE_DENSITY 4
#define MAX_TRAILS 128
#define NUM_OF_CHARS 80

uint8_t RED_THEME[]     = { 0, 32, 64, 96, 128, 160, 192, 224, 255 };
uint8_t GREEN_THEME[]   = { 0, 1, 2, 3, 4, 5, 6, 7, 255 };
uint8_t YELLOW_THEME[]  = { 0, 65, 98, 131, 164, 197, 230, 231, 255 };
uint8_t BLUE_THEME[]    = { 0, 8, 10, 16, 17, 19, 26, 28, 61, 255 };
uint8_t PURPLE_THEME[]  = { 0, 41, 48, 50, 114, 122, 155, 189, 255 };
uint8_t TEAL_THEME[]    = { 0, 10, 11, 12, 45, 87, 119, 183, 255 };
uint8_t MAGENTA_THEME[] = { 0, 72, 137, 144, 177, 217, 251, 253, 255 };

uint8_t colour_theme[COLORS_PER_THEME];

void set_colour_theme(uint8_t theme[]) {
    for (uint8_t c = 0; c < COLORS_PER_THEME; c++) {
        colour_theme[c] = theme[c];

// each character is 10 pixels tall and 8 pixels wide. i think.
// this makes the screen a 40 by 24 grid of tiles

typedef struct TILE {
    char character;
    int8_t value;
    int8_t decrement;


void update_tile(TILE* t) {
    if (t->value < 0) {
    t->value -= t->decrement;
    if (t->value < (-1 * t->decrement)) {
        t->value = 0; // sigh...

void draw_tile(TILE* t, uint24_t x, uint8_t y) {
    if (t->value < 0) {
    uint24_t draw_x = 8 * x;
    uint8_t draw_y = 10 * y;

    char draw_string[] = { t->character, '\0' };
    gfx_PrintStringXY(draw_string, draw_x, draw_y);

char* available_characters = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnoprstuvwxyz#*+=-_@~?<>&(){}[];";

char get_random_char() {
    uint8_t index = rand() % NUM_OF_CHARS;
    return available_characters[index];

typedef struct TRAIL {
    uint24_t x; uint8_t y;
    bool used;
    int8_t decrement;


void add_trail(uint8_t x) {
    for (uint8_t c = 0; c < MAX_TRAILS; c++) {
        if (trails[c].used) continue;
        TRAIL* t = &trails[c];
        t->y     = 0;
        t->x     = x;
        t->used  = true;

        t->decrement = rand() % 2 + 1;


void update_trail(TRAIL* t) {
    if (t->y >= VERT_CHARS) {
        t->used = false;
    TILE* tile      = &tiles[t->x][t->y];
    tile->character = get_random_char();
    tile->decrement = t->decrement;
    tile->value     = 8;

int main() {
    bool running = true;


    // set up the tiles
    for (uint8_t x = 0; x < HORIZ_CHARS; x++) {
        for (uint8_t y = 0; y < VERT_CHARS-1; y++) {
            tiles[x][y].value = -1;



    do {
        for (uint8_t c = 0; c < MAX_TRAILS; c++) {
        for (uint8_t x = 0; x < HORIZ_CHARS; x++) {
            for (uint8_t y = 0; y < VERT_CHARS-1; y++) {
                draw_tile(&tiles[x][y], x, y);

        for (uint8_t n = 0; n < CODE_DENSITY; n++) {
            uint8_t x = rand() % HORIZ_CHARS;
            if (tiles[x][0].value < 0) {

        running = !kb_IsDown(kb_KeyClear);

        // oh great... a mountain of if statements, Yanderedev style...
        // a necessary evil here?
        // if only there was a more elegant way to doing this...
        if (kb_IsDown(kb_Key1)) {
        if (kb_IsDown(kb_Key2)) {
        if (kb_IsDown(kb_Key3)) {
        if (kb_IsDown(kb_Key4)) {
        if (kb_IsDown(kb_Key5)) {
        if (kb_IsDown(kb_Key6)) {
        if (kb_IsDown(kb_Key7)) {
    } while (running);


    return 0;

Again, great work! I had a lot of fun messing with the code and this is definitely something I'm keeping around!
Here comes another update!

(the program runs faster on my physical calculator than it does in CEmu)

Theme saving thanks to Roccolox Programs, who brought it up on the Discord a week ago.

Also rewrote the code to use constants instead of magic numbers, as TheLastMillenial suggested. Thanks!

I still have to figure out palette swapping. And how to use sprites. I'll conquer them one at a time...

(pending review) download link: https://www.cemetech.net/downloads/files/2099/x2241
... here's another update!

As MateoConLechuga and others suggested, I've rewritten the rendering function to draw the characters as sprites instead of printing strings. I've also taken the chance to mirror the characters (some people told me about this).

Oh -- and as LogicalJoe suggested on Discord, I've also implemented direction changing.

That line of white characters at the beginning... I don't know what's causing it...

(pending review) Download link: https://www.cemetech.net/downloads/files/2099/x2260

(note to self: gotta get my act together, can't keep making joke programs forever!)
Candledark wrote:

(note to self: gotta get my act together, can't keep making joke programs forever!)

Yes you can Razz

Looks great, I'm excited to give it a try!
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum