HiveBrain v1.2.0
Get Started
← Back to all entries
patterncMinor

Matrix falling effect

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
effectmatrixfalling

Problem

How can I make this matrix effect more like the matrix movie?

#include
#include
int main()
{
srand((unsigned) time(0));
int i,j;
system("color 0a");

while(1)
{
    i = rand() % 2;
    j= rand() % 2;
    if(j)
    {
       printf("%d ", i);
    }
    else
    {
        printf(" %d", i);
    }

}
return 0;
}


Here is how it looks like:

Of course it is better if it was moving but that's all what I can show.

Also it takes a notable time to compile, is there anything wrong I'm doing?

Solution

What You Have Now:

You code is simple and concise. That in and of itself can be a desirable quality. I think we can make the code a little bit more concise while gaining some runtime efficiency.

Some changes I would make:

Change srand((unsigned) time(0)); to srand(time(NULL));

  • While both are correct, this is how I have seen seeds set more often, hence it is the idiomatic approach



Change return 0 to return EXIT_SUCCESS

  • Exit codes are included in stdlib, since you already using that library, you should also use the provided exit codes.



Change rand()%2 to rand()&1

  • The modulo operator (%) can be very inefficient on some architectures. Since you are only using rand() to get binary values, we can much more efficiently use the bitwise and operator (&) to get a 1 if the number is odd and a 0 if the number is even.



Change your while loop to remove intermediate variables:

while(1) {
 if(rand() & 1)
   printf("%d ", rand() & 1);
 else
   printf(" %d", rand() & 1);
}


All together I think you could simplify your code to this:

#include
#include
int main() {
srand(time(NULL));
system("color 0a");

while(1) {
  if(rand() & 1)
    printf("%d ", rand() & 1);
  else
    printf(" %d", rand() & 1);
}

return EXIT_SUCCESS;
}


This is a pretty small and eloquent code for generating a matrix style output. If your happy with this you can stop right here.

However, it should be pointed out that printf is a little heavy handed for just printing spaces, ones, and zeros. You could utilize putchar which will, unsurprisingly, put a character to STDOUT.

while(1) {
  if(rand() & 1) {
    putchar(48 + (rand()&1))
    putchar(' ');
  }
  else {
    putchar(' ')
    putchar(48 + (rand()&1));
  }
}


Note that now we have a Magic Number 48 in out code, that is no good! Let's let the preprocessor help us make the code a little bit more readable:

#define ASCII_NUMBER_OFFSET 48
while(1) {
  if(rand() & 1) {
    putchar(ASCII_NUMBER_OFFSET + (rand()&1));
    putchar(' ');
  }
  else {
    putchar(' ');
    putchar(ASCII_NUMBER_OFFSET + (rand()&1));
  }
}


Next is a matter of personal preference. I personally don't like 2 line if statements. If the if statement has 3 lines, it should probably be abstracted into a separate method, if it has one line, that’s perfect, but if we have 2 lines... that's murky water.

We could use the comma operator to clean up the line a little:

#define ASCII_NUMBER_OFFSET 48
while(1) {
  if(rand() & 1)
    putchar(ASCII_NUMBER_OFFSET + (rand()&2)), putchar(' ');
  else
    putchar(' '), putchar(ASCII_NUMBER_OFFSET + (rand()&1));
}


Using the comma operator is a matter of preference. I think that there are times that it is perfectly clear & reasonable to use it, others say the comma operator should never be used because it is too opaque. While that code is more compact, I don't think it helps readability or efficiency.

Lets try abstraction that into a method instead and see how that looks:

while(1) {
  if(rand() & 1)
    printLeft();
  else
    printRight();
}
.
.
.
#define ASCII_NUMBER_OFFSET 48
void printLeft() {
   putchar(' ');
   putchar(ASCII_NUMBER_OFFSET + (rand()&1));
}

void printRight() {
   putchar(ASCII_NUMBER_OFFSET + (rand()&1));
   putchar(' ');
}


That makes the while loop look better but the methods might incur some performance cost. Since your tag Optimization implies that you care most about runtime efficiency and not readability/maintainability lets try something else.

You will notice in your all the code examples above, there is some repetition in the while loop. In all the cases we have 2 statements printing the one or zero. Repetition is often a good thing to focus on because it can alert you to things that can be improved. There is a mantra of Don't Repeat Yourself (DRY) in programming which is designed to help programmers locate inefficiencies and refactor their code for better readability & efficency.

Consider this loop:

int b;
while(1) {
  if(b = rand() & 1)
    putchar(' ');
  putchar(ASCII_NUMBER_OFFSET + (rand() & 1));
  if(!b)
    putchar(' ');
}


Here we have a single binary number printing statement but conditionally print a space before or after the number. From a runtime efficiency perspective this is probably optimal (though I have not done any benchmarking).

If we put this all together we have the following:

#include
#include
#define ASCII_NUMBER_OFFSET 48

int main() {
int b;
srand(time(NULL));
system("color 0a");

while(1) {
  if(b = (rand() & 1))
    putchar(' ');
  putchar(ASCII_NUMBER_OFFSET + (rand() & 1));
  if(!b)
    putchar(' ');
}

return EXIT_SUCCESS;
}


I hope this has given you a lot of different angles to view you code from and given you the tools to decide what you value when improving this code, readability or runtime efficiency.

Code Snippets

while(1) {
 if(rand() & 1)
   printf("%d ", rand() & 1);
 else
   printf(" %d", rand() & 1);
}
#include<stdlib.h>
#include<stdio.h>
int main() {
srand(time(NULL));
system("color 0a");

while(1) {
  if(rand() & 1)
    printf("%d ", rand() & 1);
  else
    printf(" %d", rand() & 1);
}

return EXIT_SUCCESS;
}
while(1) {
  if(rand() & 1) {
    putchar(48 + (rand()&1))
    putchar(' ');
  }
  else {
    putchar(' ')
    putchar(48 + (rand()&1));
  }
}
#define ASCII_NUMBER_OFFSET 48
while(1) {
  if(rand() & 1) {
    putchar(ASCII_NUMBER_OFFSET + (rand()&1));
    putchar(' ');
  }
  else {
    putchar(' ');
    putchar(ASCII_NUMBER_OFFSET + (rand()&1));
  }
}
#define ASCII_NUMBER_OFFSET 48
while(1) {
  if(rand() & 1)
    putchar(ASCII_NUMBER_OFFSET + (rand()&2)), putchar(' ');
  else
    putchar(' '), putchar(ASCII_NUMBER_OFFSET + (rand()&1));
}

Context

StackExchange Code Review Q#46370, answer score: 2

Revisions (0)

No revisions yet.